Skip to content

Commit 3904c32

Browse files
committed
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.
1 parent 62d97d7 commit 3904c32

File tree

10 files changed

+48
-23
lines changed

10 files changed

+48
-23
lines changed

src/compiler/scala/tools/nsc/ast/TreeGen.scala

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -310,13 +310,9 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
310310
newDefDef(methSym, moveToMethod(useMethodParams(fun.body)))(tpt = TypeTree(resTp))
311311
}
312312

313-
// TODO: the rewrite to AbstractFunction is superfluous once we compile FunctionN to a SAM type (aka functional interface)
314-
def functionClassType(fun: Function): Type =
315-
if (isFunctionType(fun.tpe)) abstractFunctionType(fun.vparams.map(_.symbol.tpe), fun.body.tpe.deconst)
316-
else fun.tpe
317313

318314
def expandFunction(localTyper: analyzer.Typer)(fun: Function, inConstructorFlag: Long): Tree = {
319-
val parents = addObjectParent(addSerializable(functionClassType(fun)))
315+
val parents = addSerializable(fun.tpe)
320316
val anonClass = fun.symbol.owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation SerialVersionUIDAnnotation
321317

322318
// The original owner is used in the backend for the EnclosingMethod attribute. If fun is

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1747,17 +1747,21 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
17471747
classinfo.parents map (_.instantiateTypeParams(List(tparam), List(AnyRefTpe))),
17481748
classinfo.decls,
17491749
clazz)
1750-
clazz.setInfo {
1751-
clazz.info match {
1752-
case PolyType(tparams, _) => PolyType(tparams, newinfo)
1753-
case _ => newinfo
1754-
}
1755-
}
1750+
updatePolyClassInfo(clazz, newinfo)
17561751
FinitaryError(tparam)
17571752
}
17581753
}
17591754
}
17601755

1756+
private def updatePolyClassInfo(clazz: Symbol, newinfo: ClassInfoType): clazz.type = {
1757+
clazz.setInfo {
1758+
clazz.info match {
1759+
case PolyType(tparams, _) => PolyType(tparams, newinfo)
1760+
case _ => newinfo
1761+
}
1762+
}
1763+
}
1764+
17611765
def typedClassDef(cdef: ClassDef): Tree = {
17621766
val clazz = cdef.symbol
17631767
val typedMods = typedModifiers(cdef.mods)
@@ -1866,6 +1870,26 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
18661870
// please FIXME: uncommenting this line breaks everything
18671871
// val templ = treeCopy.Template(templ0, templ0.body, templ0.self, templ0.parents)
18681872
val clazz = context.owner
1873+
1874+
val parentTypes = parents1.map(_.tpe)
1875+
1876+
// The parents may have been normalized by typedParentTypes.
1877+
// We must update the info as well, or we won't find the super constructor for our now-first parent class
1878+
// Consider `class C ; trait T extends C ; trait U extends T`
1879+
// `U`'s info will start with parent `T`, but `typedParentTypes` will return `List(C, T)` (`== parents1`)
1880+
// now, the super call in the primary ctor will fail to find `C`'s ctor, since it bases its search on
1881+
// `U`'s info, not the trees.
1882+
//
1883+
// For correctness and performance, we restrict this rewrite to anonymous classes,
1884+
// as others have their parents in order already (it seems!), and we certainly
1885+
// don't want to accidentally rewire superclasses for e.g. the primitive value classes.
1886+
//
1887+
// TODO: Find an example of a named class needing this rewrite, I tried but couldn't find one.
1888+
if (clazz.isAnonymousClass && clazz.info.parents != parentTypes) {
1889+
// println(s"updating parents of $clazz from ${clazz.info.parents} to $parentTypes")
1890+
updatePolyClassInfo(clazz, ClassInfoType(parentTypes, clazz.info.decls, clazz))
1891+
}
1892+
18691893
clazz.annotations.map(_.completeInfo())
18701894
if (templ.symbol == NoSymbol)
18711895
templ setSymbol clazz.newLocalDummy(templ.pos)

src/reflect/scala/reflect/internal/Definitions.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,6 @@ trait Definitions extends api.StandardDefinitions {
581581
/** Creators for TupleN, ProductN, FunctionN. */
582582
def tupleType(elems: List[Type]) = TupleClass.specificType(elems)
583583
def functionType(formals: List[Type], restpe: Type) = FunctionClass.specificType(formals, restpe)
584-
def abstractFunctionType(formals: List[Type], restpe: Type) = AbstractFunctionClass.specificType(formals, restpe)
585584

586585
def wrapArrayMethodName(elemtp: Type): TermName = elemtp.typeSymbol match {
587586
case ByteClass => nme.wrapByteArray

src/reflect/scala/reflect/internal/Types.scala

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4553,11 +4553,6 @@ trait Types
45534553
else (ps :+ SerializableTpe).toList
45544554
)
45554555

4556-
def addObjectParent(tps: List[Type]) = tps match {
4557-
case hd :: _ if hd.typeSymbol.isTrait => ObjectTpe :: tps
4558-
case _ => tps
4559-
}
4560-
45614556
/** Adds the @uncheckedBound annotation if the given `tp` has type arguments */
45624557
final def uncheckedBounds(tp: Type): Type = {
45634558
if (tp.typeArgs.isEmpty || UncheckedBoundsClass == NoSymbol) tp // second condition for backwards compatibility with older scala-reflect.jar

test/files/neg/t5761.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Unspecified value parameter x.
1313
t5761.scala:13: error: not found: type Tread
1414
new Tread("sth") { }.run()
1515
^
16-
t5761.scala:13: error: value run is not a member of AnyRef
16+
t5761.scala:13: error: value run is not a member of <error>
1717
new Tread("sth") { }.run()
1818
^
1919
5 errors found

test/files/run/delambdafy_uncurry_byname_inline.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ package <empty> {
77
};
88
def bar(x: () => Int): Int = x.apply();
99
def foo(): Int = Foo.this.bar({
10-
@SerialVersionUID(value = 0) final <synthetic> class $anonfun extends scala.runtime.AbstractFunction0[Int] with Serializable {
10+
@SerialVersionUID(value = 0) final <synthetic> class $anonfun extends Object with () => Int with Serializable {
1111
def <init>(): <$anon: () => Int> = {
1212
$anonfun.super.<init>();
1313
()

test/files/run/delambdafy_uncurry_inline.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ package <empty> {
77
};
88
def bar(): Unit = {
99
val f: Int => Int = {
10-
@SerialVersionUID(value = 0) final <synthetic> class $anonfun extends scala.runtime.AbstractFunction1[Int,Int] with Serializable {
10+
@SerialVersionUID(value = 0) final <synthetic> class $anonfun extends Object with Int => Int with Serializable {
1111
def <init>(): <$anon: Int => Int> = {
1212
$anonfun.super.<init>();
1313
()

test/files/run/sammy_restrictions_LMF.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ trait TImpure { def apply(x: Int): String ; println(1) }
88
trait Println { println(1) }
99
trait TImpureSuper extends Println { def apply(x: Int): String }
1010

11+
class C
12+
trait A extends C
13+
trait B extends A
14+
trait TClassParent extends B { def apply(x: Int): String }
15+
1116
object Test extends App {
1217
final val AnonFunClass = "$anonfun$"
1318
final val LMFClass = "$$Lambda$" // LambdaMetaFactory names classes like this
@@ -45,4 +50,8 @@ object Test extends App {
4550

4651
notLMF((x => "a"): TImpure)
4752
notLMF((x => "a"): TImpureSuper)
53+
54+
val fClassParent: TClassParent = x => "a"
55+
notLMF(fClassParent)
56+
assert(fClassParent(1) == "a")
4857
}

test/files/run/t6028.check

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ package <empty> {
2424
(new <$anon: Function0>(T.this, tryyParam, tryyLocal): Function0)
2525
}
2626
};
27-
@SerialVersionUID(value = 0) final <synthetic> class $anonfun$foo$1 extends scala.runtime.AbstractFunction0$mcI$sp with Serializable {
27+
@SerialVersionUID(value = 0) final <synthetic> class $anonfun$foo$1 extends Object with Function0$mcI$sp with Serializable {
2828
def <init>($outer: T, methodParam$1: Int, methodLocal$1: Int): <$anon: Function0> = {
2929
$anonfun$foo$1.super.<init>();
30+
$anonfun$foo$1.super./*Function0*/$init$();
3031
()
3132
};
3233
final def apply(): Int = $anonfun$foo$1.this.apply$mcI$sp();
@@ -66,9 +67,10 @@ package <empty> {
6667
T.this.MethodLocalObject$lzycompute$1(barParam$1, MethodLocalObject$module$1)
6768
else
6869
MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]();
69-
@SerialVersionUID(value = 0) final <synthetic> class $anonfun$tryy$1 extends scala.runtime.AbstractFunction0$mcV$sp with Serializable {
70+
@SerialVersionUID(value = 0) final <synthetic> class $anonfun$tryy$1 extends Object with Function0$mcV$sp with Serializable {
7071
def <init>($outer: T, tryyParam$1: Int, tryyLocal$1: runtime.IntRef): <$anon: Function0> = {
7172
$anonfun$tryy$1.super.<init>();
73+
$anonfun$tryy$1.super./*Function0*/$init$();
7274
()
7375
};
7476
final def apply(): Unit = $anonfun$tryy$1.this.apply$mcV$sp();

test/files/run/t6555.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ package <empty> {
66
()
77
};
88
private[this] val f: Int => Int = {
9-
@SerialVersionUID(value = 0) final <synthetic> class $anonfun extends scala.runtime.AbstractFunction1$mcII$sp with Serializable {
9+
@SerialVersionUID(value = 0) final <synthetic> class $anonfun extends Object with Int => Int with Serializable {
1010
def <init>(): <$anon: Int => Int> = {
1111
$anonfun.super.<init>();
1212
()

0 commit comments

Comments
 (0)