aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-12-05 19:25:45 +0100
committerMartin Odersky <odersky@gmail.com>2014-12-05 19:26:24 +0100
commitfc23083675e4b194e42a0c310b1c43ab5d3aed2e (patch)
tree0d0895bebf4917a862dbb89ca2d662155acef9b9 /src
parent8336a0ddbe78b363394c48e3407b79c72008d2b3 (diff)
downloaddotty-fc23083675e4b194e42a0c310b1c43ab5d3aed2e.tar.gz
dotty-fc23083675e4b194e42a0c310b1c43ab5d3aed2e.tar.bz2
dotty-fc23083675e4b194e42a0c310b1c43ab5d3aed2e.zip
Fix by-name arguments
Previous scheme relying on Attachments was fragile. We now use a dummy method application, which transmits info reliably to Erasure.
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala5
-rw-r--r--src/dotty/tools/dotc/core/StdNames.scala1
-rw-r--r--src/dotty/tools/dotc/transform/ElimByName.scala21
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala6
4 files changed, 17 insertions, 16 deletions
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 = "<dummy-apply>"
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