From fc23083675e4b194e42a0c310b1c43ab5d3aed2e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 5 Dec 2014 19:25:45 +0100 Subject: Fix by-name arguments Previous scheme relying on Attachments was fragile. We now use a dummy method application, which transmits info reliably to Erasure. --- src/dotty/tools/dotc/core/Definitions.scala | 5 +++++ src/dotty/tools/dotc/core/StdNames.scala | 1 + src/dotty/tools/dotc/transform/ElimByName.scala | 21 +++++++++------------ src/dotty/tools/dotc/transform/Erasure.scala | 6 ++---- 4 files changed, 17 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index 895d41516..311b27717 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -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( diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala index 959e9cb84..24e948fa9 100644 --- a/src/dotty/tools/dotc/core/StdNames.scala +++ b/src/dotty/tools/dotc/core/StdNames.scala @@ -372,6 +372,7 @@ object StdNames { val delayedInit: N = "delayedInit" val delayedInitArg: N = "delayedInit$body" val drop: N = "drop" + val dummyApply: N = "" val elem: N = "elem" val emptyValDef: N = "emptyValDef" val ensureAccessible : N = "ensureAccessible" diff --git a/src/dotty/tools/dotc/transform/ElimByName.scala b/src/dotty/tools/dotc/transform/ElimByName.scala index 7adee3a8a..cb5fdbbf0 100644 --- a/src/dotty/tools/dotc/transform/ElimByName.scala +++ b/src/dotty/tools/dotc/transform/ElimByName.scala @@ -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: * @@ -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" @@ -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 } diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala index 5b70b2909..1cf0583dc 100644 --- a/src/dotty/tools/dotc/transform/Erasure.scala +++ b/src/dotty/tools/dotc/transform/Erasure.scala @@ -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 -- cgit v1.2.3