Skip to content

Fix by-name arguments #267

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 12, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,11 @@ class Definitions {
def ObjectMethods = List(Object_eq, Object_ne, Object_synchronized, Object_clone,
Object_finalize, Object_notify, Object_notifyAll, Object_wait, Object_waitL, Object_waitLI)

/** Dummy method needed by elimByName */
lazy val dummyApply = newPolyMethod(
RootClass, nme.dummyApply, 1,
pt => MethodType(List(FunctionType(Nil, PolyParam(pt, 0))), PolyParam(pt, 0)))

lazy val NotNullClass = ctx.requiredClass("scala.NotNull")

lazy val NothingClass: ClassSymbol = newCompleteClassSymbol(
Expand Down
1 change: 1 addition & 0 deletions src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ object StdNames {
val delayedInit: N = "delayedInit"
val delayedInitArg: N = "delayedInit$body"
val drop: N = "drop"
val dummyApply: N = "<dummy-apply>"
val elem: N = "elem"
val emptyValDef: N = "emptyValDef"
val ensureAccessible : N = "ensureAccessible"
Expand Down
21 changes: 9 additions & 12 deletions src/dotty/tools/dotc/transform/ElimByName.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ import util.Attachment
import core.StdNames.nme
import ast.Trees._

object ElimByName {
val ByNameArg = new Attachment.Key[Unit]
}

/** This phase eliminates ExprTypes `=> T` as types of function parameters, and replaces them by
* nullary function types. More precisely:
*
Expand All @@ -39,13 +35,15 @@ object ElimByName {
*
* This makes the argument compatible with a parameter type of () => T, which will be the
* formal parameter type at erasure. But to be -Ycheckable until then, any argument
* ARG rewritten by the rules above is again wrapped in an application ARG.apply(),
* labelled with a `ByNameParam` attachment. Erasure will later strip wrapped
* `.apply()` calls with ByNameParam attachments.
* ARG rewritten by the rules above is again wrapped in an application DummyApply(ARG)
* where
*
* DummyApply: [T](() => T): T
*
* is a synthetic method defined in Definitions. Erasure will later strip these DummyApply wrappers.
*/
class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransformer =>
import ast.tpd._
import ElimByName._

override def phaseName: String = "elimByName"

Expand All @@ -64,17 +62,16 @@ class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransform

def transformArg(arg: Tree, formal: Type): Tree = formal.dealias match {
case formalExpr: ExprType =>
val argType = arg.tpe.widen
val argFun = arg match {
case Apply(Select(qual, nme.apply), Nil) if qual.tpe derivesFrom defn.FunctionClass(0) =>
qual
case _ =>
val meth = ctx.newSymbol(
ctx.owner, nme.ANON_FUN, Synthetic | Method, MethodType(Nil, Nil, arg.tpe.widen))
ctx.owner, nme.ANON_FUN, Synthetic | Method, MethodType(Nil, Nil, argType))
Closure(meth, _ => arg.changeOwner(ctx.owner, meth))
}
val argApplied = argFun.select(defn.Function0_apply).appliedToNone
argApplied.putAttachment(ByNameArg, ())
argApplied
ref(defn.dummyApply).appliedToType(argType).appliedTo(argFun)
case _ =>
arg
}
Expand Down
6 changes: 2 additions & 4 deletions src/dotty/tools/dotc/transform/Erasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -370,10 +370,8 @@ object Erasure extends TypeTestsCasts{

override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
val Apply(fun, args) = tree
if (tree.removeAttachment(ElimByName.ByNameArg).isDefined) {
val Select(qual, nme.apply) = fun
typedUnadapted(qual, pt)
}
if (fun.symbol == defn.dummyApply)
typedUnadapted(args.head, pt)
else typedExpr(fun, FunProto(args, pt, this)) match {
case fun1: Apply => // arguments passed in prototype were already passed
fun1
Expand Down