summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@typesafe.com>2016-03-29 18:18:09 -0700
committerAdriaan Moors <adriaan.moors@typesafe.com>2016-03-29 23:19:26 -0700
commit3904c3216c741b387d81754e55aa079ce4218d06 (patch)
tree9d53968a9542a5b2791afac33d6f8fa2152b66dd
parent62d97d7f110894a0c2f36b1ed9dd7ad59c0115fa (diff)
downloadscala-3904c3216c741b387d81754e55aa079ce4218d06.tar.gz
scala-3904c3216c741b387d81754e55aa079ce4218d06.tar.bz2
scala-3904c3216c741b387d81754e55aa079ce4218d06.zip
LMF cannot instantiate SAM of trait with non-trait superclass
Also, drop AbstractFunction for parent of anonymous subclass of function type that must have its class spun up at compile time (rather than at linkage time by LambdaMetaFactory). This revealed an old problem with typedTemplate, in which parent types may be normalized at the level of trees, while this change does not get propagated to the class's info in time for the constructor to be located when we type check the primary constructor.
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala36
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala1
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala5
-rw-r--r--test/files/neg/t5761.check2
-rw-r--r--test/files/run/delambdafy_uncurry_byname_inline.check2
-rw-r--r--test/files/run/delambdafy_uncurry_inline.check2
-rw-r--r--test/files/run/sammy_restrictions_LMF.scala9
-rw-r--r--test/files/run/t6028.check6
-rw-r--r--test/files/run/t6555.check2
10 files changed, 48 insertions, 23 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index 27e366e725..227d395036 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -310,13 +310,9 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
newDefDef(methSym, moveToMethod(useMethodParams(fun.body)))(tpt = TypeTree(resTp))
}
- // TODO: the rewrite to AbstractFunction is superfluous once we compile FunctionN to a SAM type (aka functional interface)
- def functionClassType(fun: Function): Type =
- if (isFunctionType(fun.tpe)) abstractFunctionType(fun.vparams.map(_.symbol.tpe), fun.body.tpe.deconst)
- else fun.tpe
def expandFunction(localTyper: analyzer.Typer)(fun: Function, inConstructorFlag: Long): Tree = {
- val parents = addObjectParent(addSerializable(functionClassType(fun)))
+ val parents = addSerializable(fun.tpe)
val anonClass = fun.symbol.owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation SerialVersionUIDAnnotation
// The original owner is used in the backend for the EnclosingMethod attribute. If fun is
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 35cfc644ab..ff0513156b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1747,17 +1747,21 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
classinfo.parents map (_.instantiateTypeParams(List(tparam), List(AnyRefTpe))),
classinfo.decls,
clazz)
- clazz.setInfo {
- clazz.info match {
- case PolyType(tparams, _) => PolyType(tparams, newinfo)
- case _ => newinfo
- }
- }
+ updatePolyClassInfo(clazz, newinfo)
FinitaryError(tparam)
}
}
}
+ private def updatePolyClassInfo(clazz: Symbol, newinfo: ClassInfoType): clazz.type = {
+ clazz.setInfo {
+ clazz.info match {
+ case PolyType(tparams, _) => PolyType(tparams, newinfo)
+ case _ => newinfo
+ }
+ }
+ }
+
def typedClassDef(cdef: ClassDef): Tree = {
val clazz = cdef.symbol
val typedMods = typedModifiers(cdef.mods)
@@ -1866,6 +1870,26 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// please FIXME: uncommenting this line breaks everything
// val templ = treeCopy.Template(templ0, templ0.body, templ0.self, templ0.parents)
val clazz = context.owner
+
+ val parentTypes = parents1.map(_.tpe)
+
+ // The parents may have been normalized by typedParentTypes.
+ // We must update the info as well, or we won't find the super constructor for our now-first parent class
+ // Consider `class C ; trait T extends C ; trait U extends T`
+ // `U`'s info will start with parent `T`, but `typedParentTypes` will return `List(C, T)` (`== parents1`)
+ // now, the super call in the primary ctor will fail to find `C`'s ctor, since it bases its search on
+ // `U`'s info, not the trees.
+ //
+ // For correctness and performance, we restrict this rewrite to anonymous classes,
+ // as others have their parents in order already (it seems!), and we certainly
+ // don't want to accidentally rewire superclasses for e.g. the primitive value classes.
+ //
+ // TODO: Find an example of a named class needing this rewrite, I tried but couldn't find one.
+ if (clazz.isAnonymousClass && clazz.info.parents != parentTypes) {
+// println(s"updating parents of $clazz from ${clazz.info.parents} to $parentTypes")
+ updatePolyClassInfo(clazz, ClassInfoType(parentTypes, clazz.info.decls, clazz))
+ }
+
clazz.annotations.map(_.completeInfo())
if (templ.symbol == NoSymbol)
templ setSymbol clazz.newLocalDummy(templ.pos)
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 8074b448fe..e9baa47d82 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -581,7 +581,6 @@ trait Definitions extends api.StandardDefinitions {
/** Creators for TupleN, ProductN, FunctionN. */
def tupleType(elems: List[Type]) = TupleClass.specificType(elems)
def functionType(formals: List[Type], restpe: Type) = FunctionClass.specificType(formals, restpe)
- def abstractFunctionType(formals: List[Type], restpe: Type) = AbstractFunctionClass.specificType(formals, restpe)
def wrapArrayMethodName(elemtp: Type): TermName = elemtp.typeSymbol match {
case ByteClass => nme.wrapByteArray
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 00df55f044..f385ca08c9 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -4553,11 +4553,6 @@ trait Types
else (ps :+ SerializableTpe).toList
)
- def addObjectParent(tps: List[Type]) = tps match {
- case hd :: _ if hd.typeSymbol.isTrait => ObjectTpe :: tps
- case _ => tps
- }
-
/** Adds the @uncheckedBound annotation if the given `tp` has type arguments */
final def uncheckedBounds(tp: Type): Type = {
if (tp.typeArgs.isEmpty || UncheckedBoundsClass == NoSymbol) tp // second condition for backwards compatibility with older scala-reflect.jar
diff --git a/test/files/neg/t5761.check b/test/files/neg/t5761.check
index 2d66af26f6..15c0bc7634 100644
--- a/test/files/neg/t5761.check
+++ b/test/files/neg/t5761.check
@@ -13,7 +13,7 @@ Unspecified value parameter x.
t5761.scala:13: error: not found: type Tread
new Tread("sth") { }.run()
^
-t5761.scala:13: error: value run is not a member of AnyRef
+t5761.scala:13: error: value run is not a member of <error>
new Tread("sth") { }.run()
^
5 errors found
diff --git a/test/files/run/delambdafy_uncurry_byname_inline.check b/test/files/run/delambdafy_uncurry_byname_inline.check
index d96a995f44..e1ee4c29e2 100644
--- a/test/files/run/delambdafy_uncurry_byname_inline.check
+++ b/test/files/run/delambdafy_uncurry_byname_inline.check
@@ -7,7 +7,7 @@ package <empty> {
};
def bar(x: () => Int): Int = x.apply();
def foo(): Int = Foo.this.bar({
- @SerialVersionUID(value = 0) final <synthetic> class $anonfun extends scala.runtime.AbstractFunction0[Int] with Serializable {
+ @SerialVersionUID(value = 0) final <synthetic> class $anonfun extends Object with () => Int with Serializable {
def <init>(): <$anon: () => Int> = {
$anonfun.super.<init>();
()
diff --git a/test/files/run/delambdafy_uncurry_inline.check b/test/files/run/delambdafy_uncurry_inline.check
index 5521cc4a2c..479e9409fa 100644
--- a/test/files/run/delambdafy_uncurry_inline.check
+++ b/test/files/run/delambdafy_uncurry_inline.check
@@ -7,7 +7,7 @@ package <empty> {
};
def bar(): Unit = {
val f: Int => Int = {
- @SerialVersionUID(value = 0) final <synthetic> class $anonfun extends scala.runtime.AbstractFunction1[Int,Int] with Serializable {
+ @SerialVersionUID(value = 0) final <synthetic> class $anonfun extends Object with Int => Int with Serializable {
def <init>(): <$anon: Int => Int> = {
$anonfun.super.<init>();
()
diff --git a/test/files/run/sammy_restrictions_LMF.scala b/test/files/run/sammy_restrictions_LMF.scala
index 27a3d21dad..aa49e14113 100644
--- a/test/files/run/sammy_restrictions_LMF.scala
+++ b/test/files/run/sammy_restrictions_LMF.scala
@@ -8,6 +8,11 @@ trait TImpure { def apply(x: Int): String ; println(1) }
trait Println { println(1) }
trait TImpureSuper extends Println { def apply(x: Int): String }
+class C
+trait A extends C
+trait B extends A
+trait TClassParent extends B { def apply(x: Int): String }
+
object Test extends App {
final val AnonFunClass = "$anonfun$"
final val LMFClass = "$$Lambda$" // LambdaMetaFactory names classes like this
@@ -45,4 +50,8 @@ object Test extends App {
notLMF((x => "a"): TImpure)
notLMF((x => "a"): TImpureSuper)
+
+ val fClassParent: TClassParent = x => "a"
+ notLMF(fClassParent)
+ assert(fClassParent(1) == "a")
}
diff --git a/test/files/run/t6028.check b/test/files/run/t6028.check
index 532d177300..f21b77fdc7 100644
--- a/test/files/run/t6028.check
+++ b/test/files/run/t6028.check
@@ -24,9 +24,10 @@ package <empty> {
(new <$anon: Function0>(T.this, tryyParam, tryyLocal): Function0)
}
};
- @SerialVersionUID(value = 0) final <synthetic> class $anonfun$foo$1 extends scala.runtime.AbstractFunction0$mcI$sp with Serializable {
+ @SerialVersionUID(value = 0) final <synthetic> class $anonfun$foo$1 extends Object with Function0$mcI$sp with Serializable {
def <init>($outer: T, methodParam$1: Int, methodLocal$1: Int): <$anon: Function0> = {
$anonfun$foo$1.super.<init>();
+ $anonfun$foo$1.super./*Function0*/$init$();
()
};
final def apply(): Int = $anonfun$foo$1.this.apply$mcI$sp();
@@ -66,9 +67,10 @@ package <empty> {
T.this.MethodLocalObject$lzycompute$1(barParam$1, MethodLocalObject$module$1)
else
MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]();
- @SerialVersionUID(value = 0) final <synthetic> class $anonfun$tryy$1 extends scala.runtime.AbstractFunction0$mcV$sp with Serializable {
+ @SerialVersionUID(value = 0) final <synthetic> class $anonfun$tryy$1 extends Object with Function0$mcV$sp with Serializable {
def <init>($outer: T, tryyParam$1: Int, tryyLocal$1: runtime.IntRef): <$anon: Function0> = {
$anonfun$tryy$1.super.<init>();
+ $anonfun$tryy$1.super./*Function0*/$init$();
()
};
final def apply(): Unit = $anonfun$tryy$1.this.apply$mcV$sp();
diff --git a/test/files/run/t6555.check b/test/files/run/t6555.check
index e3b467ce7c..fef689a80d 100644
--- a/test/files/run/t6555.check
+++ b/test/files/run/t6555.check
@@ -6,7 +6,7 @@ package <empty> {
()
};
private[this] val f: Int => Int = {
- @SerialVersionUID(value = 0) final <synthetic> class $anonfun extends scala.runtime.AbstractFunction1$mcII$sp with Serializable {
+ @SerialVersionUID(value = 0) final <synthetic> class $anonfun extends Object with Int => Int with Serializable {
def <init>(): <$anon: Int => Int> = {
$anonfun.super.<init>();
()