summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/transform/UnCurry.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/UnCurry.scala')
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala41
1 files changed, 39 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 79a77d7a0c..57639a94c7 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -703,9 +703,46 @@ abstract class UnCurry extends InfoTransform
// declared type and assign this to a synthetic val. Later, we'll patch
// the method body to refer to this, rather than the parameter.
val tempVal: ValDef = {
+ // SI-9442: using the "uncurry-erased" type (the one after the uncurry phase) can lead to incorrect
+ // tree transformations. For example, compiling:
+ // ```
+ // def foo(c: Ctx)(l: c.Tree): Unit = {
+ // val l2: c.Tree = l
+ // }
+ // ```
+ // Results in the following AST:
+ // ```
+ // def foo(c: Ctx, l: Ctx#Tree): Unit = {
+ // val l$1: Ctx#Tree = l.asInstanceOf[Ctx#Tree]
+ // val l2: c.Tree = l$1 // no, not really, it's not.
+ // }
+ // ```
+ // Of course, this is incorrect, since `l$1` has type `Ctx#Tree`, which is not a subtype of `c.Tree`.
+ //
+ // So what we need to do is to use the pre-uncurry type when creating `l$1`, which is `c.Tree` and is
+ // correct. Now, there are two additional problems:
+ // 1. when varargs and byname params are involved, the uncurry transformation desugares these special
+ // cases to actual typerefs, eg:
+ // ```
+ // T* ~> Seq[T] (Scala-defined varargs)
+ // T* ~> Array[T] (Java-defined varargs)
+ // =>T ~> Function0[T] (by name params)
+ // ```
+ // we use the DesugaredParameterType object (defined in scala.reflect.internal.transform.UnCurry)
+ // to redo this desugaring manually here
+ // 2. the type needs to be normalized, since `gen.mkCast` checks this (no HK here, just aliases have
+ // to be expanded before handing the type to `gen.mkAttributedCast`, which calls `gen.mkCast`)
+ val info0 =
+ enteringUncurry(p.symbol.info) match {
+ case DesugaredParameterType(desugaredTpe) =>
+ desugaredTpe
+ case tpe =>
+ tpe
+ }
+ val info = info0.normalize
val tempValName = unit freshTermName (p.name + "$")
- val newSym = dd.symbol.newTermSymbol(tempValName, p.pos, SYNTHETIC).setInfo(p.symbol.info)
- atPos(p.pos)(ValDef(newSym, gen.mkAttributedCast(Ident(p.symbol), p.symbol.info)))
+ val newSym = dd.symbol.newTermSymbol(tempValName, p.pos, SYNTHETIC).setInfo(info)
+ atPos(p.pos)(ValDef(newSym, gen.mkAttributedCast(Ident(p.symbol), info)))
}
Packed(newParam, tempVal)
}