Skip to content

Commit 56e9a93

Browse files
authored
Merge pull request #15703 from dotty-staging/init-super-accessor
Handle super accessors in initialization checker
2 parents 67f11ff + f98b23b commit 56e9a93

File tree

5 files changed

+113
-17
lines changed

5 files changed

+113
-17
lines changed

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

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Symbols.*
88
import Types.*
99
import StdNames.*
1010
import NameKinds.OuterSelectName
11+
import NameKinds.SuperAccessorName
1112

1213
import ast.tpd.*
1314
import config.Printers.init as printer
@@ -788,7 +789,9 @@ object Semantic:
788789
if !needResolve then
789790
meth
790791
else if superType.exists then
791-
resolveSuper(ref.klass, superType, meth)
792+
meth
793+
else if meth.name.is(SuperAccessorName) then
794+
ResolveSuper.rebindSuper(ref.klass, meth)
792795
else
793796
resolve(ref.klass, meth)
794797

@@ -829,7 +832,7 @@ object Semantic:
829832
value.select(target, receiver, needResolve = false)
830833
else
831834
if ref.klass.isSubClass(receiver.widenSingleton.classSymbol) then
832-
report.error("Unexpected resolution failure: ref.klass = " + ref.klass.show + ", meth = " + meth.show + Trace.show, Trace.position)
835+
report.error("[Internal error] Unexpected resolution failure: ref.klass = " + ref.klass.show + ", meth = " + meth.show + Trace.show, Trace.position)
833836
Hot
834837
else
835838
// This is possible due to incorrect type cast.
@@ -1175,9 +1178,8 @@ object Semantic:
11751178
// Note that a parameterized trait may only get parameters from the class that extends the trait.
11761179
// A trait may not supply constructor arguments to another trait.
11771180
if !klass.is(Flags.Trait) then
1178-
for parent <- klass.parentSyms if parent.hasSource do doPromote(parent.asClass, klass, isHotSegment)
1179-
// We still need to handle indirectly extended traits via traits, which are not in the parent list.
11801181
val superCls = klass.superClass
1182+
if superCls.hasSource then doPromote(superCls.asClass, klass, isHotSegment)
11811183
val mixins = klass.baseClasses.tail.takeWhile(_ != superCls)
11821184
for mixin <- mixins if mixin.hasSource do doPromote(mixin.asClass, klass, isHotSegment)
11831185
end doPromote
@@ -1768,16 +1770,3 @@ object Semantic:
17681770
if (sym.isEffectivelyFinal || sym.isConstructor) sym
17691771
else sym.matchingMember(cls.appliedRef)
17701772
}
1771-
1772-
def resolveSuper(cls: ClassSymbol, superType: Type, sym: Symbol)(using Context): Symbol =
1773-
import annotation.tailrec
1774-
@tailrec def loop(bcs: List[ClassSymbol]): Symbol = bcs match {
1775-
case bc :: bcs1 =>
1776-
val cand = sym.matchingDecl(bcs.head, cls.thisType)
1777-
.suchThat(alt => !alt.is(Flags.Deferred)).symbol
1778-
if (cand.exists) cand else loop(bcs.tail)
1779-
case _ =>
1780-
NoSymbol
1781-
}
1782-
loop(cls.info.baseClasses.dropWhile(sym.owner != _))
1783-

tests/init/neg/super-resolution.check

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
-- Error: tests/init/neg/super-resolution.scala:21:6 -------------------------------------------------------------------
2+
21 | val m = 30 // error
3+
| ^
4+
| Access non-initialized value m. Calling trace:
5+
| -> class C extends A with M with N: [ super-resolution.scala:17 ]
6+
| ^
7+
| -> foo() [ super-resolution.scala:18 ]
8+
| ^^^^^
9+
| -> override def foo(): Int = b * super.foo() [ super-resolution.scala:15 ]
10+
| ^^^^^^^^^^^
11+
| -> override def foo(): Int = a + super.foo() [ super-resolution.scala:11 ]
12+
| ^^^^^^^^^^^
13+
| -> def foo(): Int = m [ super-resolution.scala:7 ]
14+
| ^
15+
-- Error: tests/init/neg/super-resolution.scala:19:6 -------------------------------------------------------------------
16+
19 | val a = 10 // error
17+
| ^
18+
| Access non-initialized value a. Calling trace:
19+
| -> class C extends A with M with N: [ super-resolution.scala:17 ]
20+
| ^
21+
| -> foo() [ super-resolution.scala:18 ]
22+
| ^^^^^
23+
| -> override def foo(): Int = b * super.foo() [ super-resolution.scala:15 ]
24+
| ^^^^^^^^^^^
25+
| -> override def foo(): Int = a + super.foo() [ super-resolution.scala:11 ]
26+
| ^
27+
-- Error: tests/init/neg/super-resolution.scala:20:6 -------------------------------------------------------------------
28+
20 | val b = 20 // error
29+
| ^
30+
| Access non-initialized value b. Calling trace:
31+
| -> class C extends A with M with N: [ super-resolution.scala:17 ]
32+
| ^
33+
| -> foo() [ super-resolution.scala:18 ]
34+
| ^^^^^
35+
| -> override def foo(): Int = b * super.foo() [ super-resolution.scala:15 ]
36+
| ^

tests/init/neg/super-resolution.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
abstract class A:
2+
val n: Int
3+
def foo(): Int = n
4+
5+
trait B:
6+
val m: Int
7+
def foo(): Int = m
8+
9+
trait M extends A with B:
10+
val a: Int
11+
override def foo(): Int = a + super.foo()
12+
13+
trait N extends A with B:
14+
val b: Int
15+
override def foo(): Int = b * super.foo()
16+
17+
class C extends A with M with N:
18+
foo()
19+
val a = 10 // error
20+
val b = 20 // error
21+
val m = 30 // error
22+
val n = 40
23+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-- Error: tests/init/neg/super-resolution2.scala:19:6 ------------------------------------------------------------------
2+
19 | val n = 40 // error
3+
| ^
4+
| Access non-initialized value n. Calling trace:
5+
| -> class N extends A with B: [ super-resolution2.scala:9 ]
6+
| ^
7+
| -> new Inner [ super-resolution2.scala:16 ]
8+
| ^^^^^^^^^
9+
| -> class Inner: [ super-resolution2.scala:12 ]
10+
| ^
11+
| -> N.super[A].foo() [ super-resolution2.scala:13 ]
12+
| ^^^^^^^^^^^^^^^^
13+
| -> def foo(): Int = n [ super-resolution2.scala:3 ]
14+
| ^
15+
-- Error: tests/init/neg/super-resolution2.scala:18:6 ------------------------------------------------------------------
16+
18 | val m = 30 // error
17+
| ^
18+
| Access non-initialized value m. Calling trace:
19+
| -> class N extends A with B: [ super-resolution2.scala:9 ]
20+
| ^
21+
| -> new Inner [ super-resolution2.scala:16 ]
22+
| ^^^^^^^^^
23+
| -> class Inner: [ super-resolution2.scala:12 ]
24+
| ^
25+
| -> N.super.foo() [ super-resolution2.scala:14 ]
26+
| ^^^^^^^^^^^^^
27+
| -> def foo(): Int = m [ super-resolution2.scala:7 ]
28+
| ^
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
abstract class A:
2+
val n: Int
3+
def foo(): Int = n
4+
5+
trait B:
6+
val m: Int
7+
def foo(): Int = m
8+
9+
class N extends A with B:
10+
override def foo(): Int = a * super.foo()
11+
12+
class Inner:
13+
N.super[A].foo()
14+
N.super.foo()
15+
16+
new Inner
17+
18+
val m = 30 // error
19+
val n = 40 // error
20+
val a = 50

0 commit comments

Comments
 (0)