Skip to content

Commit e4b9ca9

Browse files
committed
Check if the parent of class has an empty constr before expanding SAM
Expanding a SAM into an anonymous class assumes that the parent class has a constructor with an empty parameter list. Before this change, a situation in which there was no such constructor caused a crash. fixes scala#15855
1 parent e560c2d commit e4b9ca9

File tree

2 files changed

+76
-2
lines changed

2 files changed

+76
-2
lines changed

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,12 @@ class ExpandSAMs extends MiniPhase:
5959
case tpe =>
6060
val tpe1 = checkRefinements(tpe.stripNull, fn)
6161
val Seq(samDenot) = tpe1.possibleSamMethods
62-
cpy.Block(tree)(stats,
63-
AnonClass(tpe1 :: Nil, fn.symbol.asTerm :: Nil, samDenot.symbol.asTerm.name :: Nil))
62+
if hasNoArgConstr(tpe1) then
63+
cpy.Block(tree)(stats,
64+
AnonClass(tpe1 :: Nil, fn.symbol.asTerm :: Nil, samDenot.symbol.asTerm.name :: Nil))
65+
else
66+
report.error(em"${tpe1} cannot be instantiated with an empty constructor", tree.srcPos)
67+
tree
6468
}
6569
case _ =>
6670
tree
@@ -182,4 +186,18 @@ class ExpandSAMs extends MiniPhase:
182186
case tpe =>
183187
tpe
184188
}
189+
190+
private def hasNoArgConstr(tpe: Type)(using Context): Boolean = {
191+
def noArgs(ctpe: Type): Boolean = ctpe match {
192+
case ctpe: PolyType =>
193+
noArgs(ctpe.resType)
194+
case ctpe: MethodType =>
195+
ctpe.paramInfos.isEmpty
196+
case _ =>
197+
false
198+
}
199+
val parent :: _ = tpe.parents: @unchecked
200+
val constr = parent.dealias.decl(nme.CONSTRUCTOR).suchThat(constr => noArgs(constr.info))
201+
constr != SymDenotations.NoDenotation
202+
}
185203
end ExpandSAMs

tests/neg/i15855.scala

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
class MyFunction(arg: String) {
2+
def a: String = arg
3+
}
4+
5+
trait MyFun[+R] extends MyFunction {
6+
def apply(i: Int): R
7+
}
8+
9+
val myFun: MyFun[Int] = (i: Int) => 1 // error
10+
11+
//
12+
13+
class MyFunction1(arg: String = "") {
14+
def a: String = arg
15+
}
16+
17+
trait MyFun1[+R] extends MyFunction1 {
18+
def apply(i: Int): R
19+
}
20+
21+
val myFun1: MyFun1[Int] = (i: Int) => 1 // error
22+
23+
//
24+
25+
trait MyFunction2(arg: String = "") {
26+
def a: String = arg
27+
}
28+
29+
trait MyFun2[+R] extends MyFunction2 {
30+
def apply(i: Int): R
31+
}
32+
33+
val myFun2: MyFun2[Int] = (i: Int) => 1
34+
35+
//
36+
37+
trait MyFunction3(arg: String) {
38+
def a: String = arg
39+
}
40+
41+
trait MyFun3[+R] extends MyFunction3 {
42+
def apply(i: Int): R
43+
}
44+
45+
val myFun3: MyFun3[Int] = (i: Int) => 1
46+
47+
//
48+
49+
class MyFunction4() {
50+
}
51+
52+
trait MyFun4[+R] extends MyFunction4 {
53+
def apply(i: Int): R
54+
}
55+
56+
val myFun4: MyFun4[Int] = (i: Int) => 1

0 commit comments

Comments
 (0)