Skip to content

Commit aa877b7

Browse files
committed
Fix initializing parents of AnonClasses
Previously creating ClassDefs of AnonClasses was only possible if the parent class had a constructor wih an empty parameter list. Otherwise the compiler would crash becasue of calling `asTerm` on a `NoSymbol`. This PR adds logic that handles callig parent constructors with default or repeated parameters. And also fails more gracefuly if no instance can be created. fixes lampepfl#15855
1 parent e560c2d commit aa877b7

File tree

5 files changed

+146
-10
lines changed

5 files changed

+146
-10
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -292,23 +292,58 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
292292
def TypeDef(sym: TypeSymbol)(using Context): TypeDef =
293293
ta.assignType(untpd.TypeDef(sym.name, TypeTree(sym.info)), sym)
294294

295-
def ClassDef(cls: ClassSymbol, constr: DefDef, body: List[Tree], superArgs: List[Tree] = Nil)(using Context): TypeDef = {
295+
def ClassDef(cls: ClassSymbol, constrDef: DefDef, body: List[Tree])(using Context): TypeDef = {
296296
val firstParent :: otherParents = cls.info.parents: @unchecked
297297
val superRef =
298298
if (cls.is(Trait)) TypeTree(firstParent)
299299
else {
300-
def isApplicable(ctpe: Type): Boolean = ctpe match {
301-
case ctpe: PolyType =>
302-
isApplicable(ctpe.instantiate(firstParent.argTypes))
303-
case ctpe: MethodType =>
304-
(superArgs corresponds ctpe.paramInfos)(_.tpe <:< _)
300+
def fromRepeated(tpe: Type): Type = tpe match {
301+
case AnnotatedType(AppliedType(base, List(tparam)), annot) if annot.symbol == defn.RepeatedAnnot =>
302+
tparam
305303
case _ =>
306-
false
304+
NoType
307305
}
308-
val constr = firstParent.decl(nme.CONSTRUCTOR).suchThat(constr => isApplicable(constr.info))
309-
New(firstParent, constr.symbol.asTerm, superArgs)
306+
307+
def canConstructMethod(constrSym: Symbol): Boolean = constrSym.info match {
308+
case ctpe: MethodOrPoly =>
309+
constrSym.paramSymss.flatten.filter(_.isTerm).forall { paramSym =>
310+
paramSym.flags.is(Flags.HasDefault) || (fromRepeated(paramSym.info) != NoType)
311+
}
312+
case _ => false
313+
}
314+
315+
def constructParent(constr: Tree): Tree = {
316+
constr.symbol.paramSymss.filter(!_.exists(_.isType)).foldLeft(constr) { (acc, paramList) =>
317+
acc.appliedToTermArgs(paramList.zipWithIndex.collect {
318+
case (paramSym, idx) if paramSym.flags.is(Flags.HasDefault) =>
319+
typer.Applications.defaultArgument(acc, idx, false)
320+
case (paramSym, idx) if fromRepeated(paramSym.info) != NoType =>
321+
tpd.ref(defn.NilModule)
322+
})
323+
}
324+
}
325+
326+
val tycon = firstParent.typeConstructor
327+
val newTree = New(tycon)
328+
.withSpan(cls.span)
329+
val constr = firstParent
330+
.decl(nme.CONSTRUCTOR)
331+
.suchThat{ constr =>
332+
canConstructMethod(constr)
333+
}
334+
335+
if constr.exists then
336+
constructParent(
337+
newTree
338+
.select(TermRef(tycon, constr.symbol.asTerm))
339+
.appliedToTypes(firstParent.argTypes)
340+
)
341+
else
342+
val msg = em"not enough arguments for constructor ${firstParent.dealias.typeSymbol.primaryConstructor.info}"
343+
report.error(msg, cls.sourcePos)
344+
EmptyTree
310345
}
311-
ClassDefWithParents(cls, constr, superRef :: otherParents.map(TypeTree(_)), body)
346+
ClassDefWithParents(cls, constrDef, superRef :: otherParents.map(TypeTree(_)), body)
312347
}
313348

314349
def ClassDefWithParents(cls: ClassSymbol, constr: DefDef, parents: List[Tree], body: List[Tree])(using Context): TypeDef = {

compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,4 +182,5 @@ class ExpandSAMs extends MiniPhase:
182182
case tpe =>
183183
tpe
184184
}
185+
185186
end ExpandSAMs

tests/neg/i15855.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class MyFunction(arg: String)
2+
3+
trait MyFun[+R] extends MyFunction {
4+
def apply(i: Int): R
5+
}
6+
7+
val myFun: MyFun[Int] = (i: Int) => 1 // error

tests/run/i15855.check

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
default
2+
List()
3+
other
4+
asdf
5+
420
6+
21.37
7+
1
8+
2
9+
3
10+
4
11+
5

tests/run/i15855.scala

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
class MyFunction1()
2+
3+
trait MyFun1[+R] extends MyFunction1 {
4+
def apply(i: Int): R
5+
}
6+
7+
val myFun1: MyFun1[Int] = (i: Int) => 1
8+
9+
//
10+
11+
class MyFunction2(arg: String = "default") {
12+
println(arg)
13+
}
14+
15+
trait MyFun2[+R] extends MyFunction2 {
16+
def apply(i: Int): R
17+
}
18+
19+
val myFun2: MyFun2[Int] = (i: Int) => 2
20+
21+
//
22+
23+
class MyFunction3(arg: String*) {
24+
println(arg)
25+
}
26+
27+
trait MyFun3[+R] extends MyFunction3 {
28+
def apply(i: Int): R
29+
}
30+
31+
val myFun3: MyFun3[Int] = (i: Int) => 3
32+
33+
//
34+
35+
class MyFunction4(arg: String) {
36+
println(arg)
37+
def this() = {
38+
this("other")
39+
}
40+
}
41+
42+
trait MyFun4[+R] extends MyFunction4 {
43+
def apply(i: Int): R
44+
}
45+
46+
val myFun4: MyFun4[Int] = (i: Int) => 4
47+
48+
//
49+
50+
class MyFunction5(arg: String = "asdf")(arg1: Int = 420, arg2: Double = 21.37) {
51+
println(arg)
52+
println(arg1)
53+
println(arg2)
54+
}
55+
56+
trait MyFun5[+R] extends MyFunction5 {
57+
def apply(i: Int): R
58+
}
59+
60+
val myFun5: MyFun5[Int] = (i: Int) => 5
61+
62+
//
63+
64+
trait Equiv[T] extends Any with Serializable {
65+
def equiv(x: T, y: T): Boolean
66+
}
67+
68+
def reference[T <: AnyRef]: Equiv[T] = { _ eq _ }
69+
def universal[T]: Equiv[T] = { _ == _ }
70+
def fromFunction[T](cmp: (T, T) => Boolean): Equiv[T] = {
71+
(x, y) => cmp(x, y)
72+
}
73+
74+
//
75+
76+
object Test extends App {
77+
println(myFun1(1))
78+
println(myFun2(1))
79+
println(myFun3(1))
80+
println(myFun4(1))
81+
println(myFun5(1))
82+
}

0 commit comments

Comments
 (0)