Skip to content

Commit 6b336f8

Browse files
committed
SI-9442 Fix the uncurry-erasure types
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`)
1 parent f8a6d21 commit 6b336f8

File tree

4 files changed

+69
-10
lines changed

4 files changed

+69
-10
lines changed

src/compiler/scala/tools/nsc/transform/UnCurry.scala

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -691,9 +691,46 @@ abstract class UnCurry extends InfoTransform
691691
// declared type and assign this to a synthetic val. Later, we'll patch
692692
// the method body to refer to this, rather than the parameter.
693693
val tempVal: ValDef = {
694+
// SI-9442: using the "uncurry-erased" type (the one after the uncurry phase) can lead to incorrect
695+
// tree transformations. For example, compiling:
696+
// ```
697+
// def foo(c: Ctx)(l: c.Tree): Unit = {
698+
// val l2: c.Tree = l
699+
// }
700+
// ```
701+
// Results in the following AST:
702+
// ```
703+
// def foo(c: Ctx, l: Ctx#Tree): Unit = {
704+
// val l$1: Ctx#Tree = l.asInstanceOf[Ctx#Tree]
705+
// val l2: c.Tree = l$1 // no, not really, it's not.
706+
// }
707+
// ```
708+
// Of course, this is incorrect, since `l$1` has type `Ctx#Tree`, which is not a subtype of `c.Tree`.
709+
//
710+
// So what we need to do is to use the pre-uncurry type when creating `l$1`, which is `c.Tree` and is
711+
// correct. Now, there are two additional problems:
712+
// 1. when varargs and byname params are involved, the uncurry transformation desugares these special
713+
// cases to actual typerefs, eg:
714+
// ```
715+
// T* ~> Seq[T] (Scala-defined varargs)
716+
// T* ~> Array[T] (Java-defined varargs)
717+
// =>T ~> Function0[T] (by name params)
718+
// ```
719+
// we use the DesugaredParameterType object (defined in scala.reflect.internal.transform.UnCurry)
720+
// to redo this desugaring manually here
721+
// 2. the type needs to be normalized, since `gen.mkCast` checks this (no HK here, just aliases have
722+
// to be expanded before handing the type to `gen.mkAttributedCast`, which calls `gen.mkCast`)
723+
val info0 =
724+
enteringUncurry(p.symbol.info) match {
725+
case DesugaredParameterType(desugaredTpe) =>
726+
desugaredTpe
727+
case tpe =>
728+
tpe
729+
}
730+
val info = info0.normalize
694731
val tempValName = unit freshTermName (p.name + "$")
695-
val newSym = dd.symbol.newTermSymbol(tempValName, p.pos, SYNTHETIC).setInfo(p.symbol.info)
696-
atPos(p.pos)(ValDef(newSym, gen.mkAttributedCast(Ident(p.symbol), p.symbol.info)))
732+
val newSym = dd.symbol.newTermSymbol(tempValName, p.pos, SYNTHETIC).setInfo(info)
733+
atPos(p.pos)(ValDef(newSym, gen.mkAttributedCast(Ident(p.symbol), info)))
697734
}
698735
Packed(newParam, tempVal)
699736
}

src/reflect/scala/reflect/internal/transform/UnCurry.scala

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,27 @@ trait UnCurry {
4040
apply(MethodType(h.cloneSymbol.resetFlag(IMPLICIT) :: t, restpe))
4141
case NullaryMethodType(restpe) =>
4242
apply(MethodType(List(), restpe))
43-
case TypeRef(pre, ByNameParamClass, arg :: Nil) =>
44-
apply(functionType(List(), arg))
45-
case TypeRef(pre, RepeatedParamClass, arg :: Nil) =>
46-
apply(seqType(arg))
47-
case TypeRef(pre, JavaRepeatedParamClass, arg :: Nil) =>
48-
apply(arrayType(
49-
if (isUnboundedGeneric(arg)) ObjectTpe else arg))
43+
case DesugaredParameterType(desugaredTpe) =>
44+
apply(desugaredTpe)
5045
case _ =>
5146
expandAlias(mapOver(tp))
5247
}
5348
}
5449
}
5550

51+
object DesugaredParameterType {
52+
def unapply(tpe: Type): Option[Type] = tpe match {
53+
case TypeRef(pre, ByNameParamClass, arg :: Nil) =>
54+
Some(functionType(List(), arg))
55+
case TypeRef(pre, RepeatedParamClass, arg :: Nil) =>
56+
Some(seqType(arg))
57+
case TypeRef(pre, JavaRepeatedParamClass, arg :: Nil) =>
58+
Some(arrayType(if (isUnboundedGeneric(arg)) ObjectTpe else arg))
59+
case _ =>
60+
None
61+
}
62+
}
63+
5664
private val uncurryType = new TypeMap {
5765
def apply(tp0: Type): Type = {
5866
val tp = expandAlias(tp0)

src/reflect/scala/reflect/runtime/JavaUniverseForce.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
444444
definitions.ScalaValueClassesNoUnit
445445
definitions.ScalaValueClasses
446446

447-
447+
uncurry.DesugaredParameterType
448448
erasure.GenericArray
449449
erasure.scalaErasure
450450
erasure.specialScalaErasure

test/files/pos/t9442.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
trait Ctx {
2+
trait Tree
3+
}
4+
trait Lst[+A] {
5+
def zip[A1 >: A, B](that: Lst[B]): Nothing
6+
}
7+
class C[@specialized(Int) T] {
8+
def moo(t: T) = {
9+
def foo1(c: Ctx)(l: Lst[c.Tree]) = l zip l
10+
def foo2(c: Ctx)(l: Lst[c.Tree]*) = l(0) zip l(1)
11+
def foo3(c: Ctx)(l: => Lst[c.Tree]) = l zip l
12+
???
13+
}
14+
}

0 commit comments

Comments
 (0)