Skip to content

Commit 7f91775

Browse files
committed
Alternative fix: abstract parameters of non-local constructor parameters as cold
1 parent 41807c9 commit 7f91775

File tree

5 files changed

+33
-41
lines changed

5 files changed

+33
-41
lines changed

compiler/src/dotty/tools/dotc/transform/init/Errors.scala

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,4 @@ object Errors {
105105
}.mkString)
106106
}
107107
}
108-
109-
/** The checker ignores local classes inside constructors
110-
*
111-
* TODO: remove this restriction.
112-
*/
113-
case class LocalClassInConstructor(klass: ClassSymbol, source: Tree, trace: Seq[Tree]) extends Error {
114-
def show(using Context): String = "Check is skipped for local classes inside constructors."
115-
}
116108
}

compiler/src/dotty/tools/dotc/transform/init/Semantic.scala

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -474,24 +474,15 @@ class Semantic {
474474
Result(Hot, error :: Nil)
475475

476476
case addr: Addr =>
477-
def inSecondaryConstructor(sym: Symbol): Boolean =
478-
!sym.isClass && (sym.isConstructor || inSecondaryConstructor(sym.owner))
479-
480-
// Approximate instances of local classes inside secondary constructor as Cold.
481-
// This way, we avoid complicating the domain for Warm unnecessarily
482-
if inSecondaryConstructor(klass.owner) then
483-
val error = LocalClassInConstructor(klass, source, trace.toVector)
484-
Result(Cold, error :: Nil)
485-
else
486-
given Trace = trace1
487-
// widen the outer to finitize addresses
488-
val outer = addr match
489-
case Warm(_, _: Warm, _, _) => Cold
490-
case _ => addr
477+
given Trace = trace1
478+
// widen the outer to finitize addresses
479+
val outer = addr match
480+
case Warm(_, _: Warm, _, _) => Cold
481+
case _ => addr
491482

492-
val value = Warm(klass, outer, ctor, args.map(_.value).widenArgs).ensureExists
493-
val res = value.call(ctor, args, superType = NoType, source)
494-
Result(value, res.errors)
483+
val value = Warm(klass, outer, ctor, args.map(_.value).widenArgs).ensureExists
484+
val res = value.call(ctor, args, superType = NoType, source)
485+
Result(value, res.errors)
495486

496487
case Fun(body, thisV, klass, env) =>
497488
report.error("unexpected tree in instantiating a function, fun = " + body.show, source)
@@ -896,13 +887,18 @@ class Semantic {
896887

897888
def default() = Result(Hot, Nil)
898889

899-
if sym.is(Flags.Param) && sym.owner.isConstructor && sym.isContainedIn(klass) then
890+
if sym.is(Flags.Param) && sym.owner.isConstructor then
900891
// instances of local classes inside secondary constructors cannot
901892
// reach here, as those values are abstracted by Cold instead of Warm.
902893
// This enables us to simplify the domain without sacrificing
903894
// expressiveness nor soundess, as local classes inside secondary
904895
// constructors are uncommon.
905-
Result(env.lookup(sym), Nil)
896+
if sym.isContainedIn(klass) then
897+
Result(env.lookup(sym), Nil)
898+
else
899+
// We don't know much about secondary constructor parameters in outer scope.
900+
// It's always safe to approximate them with `Cold`.
901+
Result(Cold, Nil)
906902
else
907903
default()
908904

tests/init/neg/secondary-ctor2.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ class A(b: B, x: Int) {
22
def this(b: B) = {
33
this(b, 5)
44
class Inner() {
5-
def foo() = println(b.n)
5+
def foo() = println(b.n) // error: calling method on cold
66
}
7-
Inner().foo() // error: calling method on cold
7+
Inner().foo()
88

99
val f = () => new A(b, 3)
1010
f() // ok

tests/init/neg/secondary-ctor3.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ def foo() =
77
def this(b: B) = {
88
this(b, 5)
99
class Inner() {
10-
def foo() = println(b.n)
10+
def foo() = println(b.n) // error
1111
}
12-
Inner().foo() // error: calling method on cold
12+
Inner().foo()
1313

1414
val l1 = new L1(3)
1515
println(l1.n)

tests/init/neg/secondary-ctor4.scala

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,29 @@
1+
trait D {
2+
val n: Int = 10
3+
}
4+
15
class M(x: Int) {
26

3-
def this(s: String) = {
4-
this(s.size)
7+
def this(d: D) = {
8+
this(d.n)
59

610
class L1(x: Int) { val n: Int = 5 }
711

812
class A(b: B, x: Int) {
9-
println(s.size)
13+
println(d.n) // error
1014

1115
class L2(x: Int) { val n: Int = 5 }
1216

1317
def this(b: B) = {
1418
this(b, 5)
15-
println(s.size)
19+
println(d.n) // error
1620

1721
class Inner() {
18-
println(s.size)
19-
println(b.n)
20-
def foo() = println(b.n)
22+
println(d.n) // error
23+
println(b.n) // error
24+
def foo() = println(b.n) // error
2125
}
22-
Inner().foo() // error: calling method on cold
26+
Inner().foo()
2327

2428
val l1 = new L1(3)
2529
println(l1.n)
@@ -35,7 +39,7 @@ class M(x: Int) {
3539
val n: Int = 10
3640
}
3741

38-
new A(new B(new D)) // error
42+
new A(new B(new D))
3943

4044
trait T {
4145
val m: Int = 10
@@ -52,6 +56,6 @@ class M(x: Int) {
5256
}
5357
}
5458

55-
class N extends M("hello") {
59+
class N(d: D) extends M(d) {
5660
val msg = "Scala"
5761
}

0 commit comments

Comments
 (0)