diff --git a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala index 4765066d571f..f9dbea1f4c1d 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala @@ -8,6 +8,7 @@ import Symbols.* import Types.* import StdNames.* import NameKinds.OuterSelectName +import NameKinds.SuperAccessorName import ast.tpd.* import config.Printers.init as printer @@ -788,7 +789,9 @@ object Semantic: if !needResolve then meth else if superType.exists then - resolveSuper(ref.klass, superType, meth) + meth + else if meth.name.is(SuperAccessorName) then + ResolveSuper.rebindSuper(ref.klass, meth) else resolve(ref.klass, meth) @@ -829,7 +832,7 @@ object Semantic: value.select(target, receiver, needResolve = false) else if ref.klass.isSubClass(receiver.widenSingleton.classSymbol) then - report.error("Unexpected resolution failure: ref.klass = " + ref.klass.show + ", meth = " + meth.show + Trace.show, Trace.position) + report.error("[Internal error] Unexpected resolution failure: ref.klass = " + ref.klass.show + ", meth = " + meth.show + Trace.show, Trace.position) Hot else // This is possible due to incorrect type cast. @@ -1175,9 +1178,8 @@ object Semantic: // Note that a parameterized trait may only get parameters from the class that extends the trait. // A trait may not supply constructor arguments to another trait. if !klass.is(Flags.Trait) then - for parent <- klass.parentSyms if parent.hasSource do doPromote(parent.asClass, klass, isHotSegment) - // We still need to handle indirectly extended traits via traits, which are not in the parent list. val superCls = klass.superClass + if superCls.hasSource then doPromote(superCls.asClass, klass, isHotSegment) val mixins = klass.baseClasses.tail.takeWhile(_ != superCls) for mixin <- mixins if mixin.hasSource do doPromote(mixin.asClass, klass, isHotSegment) end doPromote @@ -1768,16 +1770,3 @@ object Semantic: if (sym.isEffectivelyFinal || sym.isConstructor) sym else sym.matchingMember(cls.appliedRef) } - - def resolveSuper(cls: ClassSymbol, superType: Type, sym: Symbol)(using Context): Symbol = - import annotation.tailrec - @tailrec def loop(bcs: List[ClassSymbol]): Symbol = bcs match { - case bc :: bcs1 => - val cand = sym.matchingDecl(bcs.head, cls.thisType) - .suchThat(alt => !alt.is(Flags.Deferred)).symbol - if (cand.exists) cand else loop(bcs.tail) - case _ => - NoSymbol - } - loop(cls.info.baseClasses.dropWhile(sym.owner != _)) - diff --git a/tests/init/neg/super-resolution.check b/tests/init/neg/super-resolution.check new file mode 100644 index 000000000000..d5fdd2a3e59e --- /dev/null +++ b/tests/init/neg/super-resolution.check @@ -0,0 +1,36 @@ +-- Error: tests/init/neg/super-resolution.scala:21:6 ------------------------------------------------------------------- +21 | val m = 30 // error + | ^ + | Access non-initialized value m. Calling trace: + | -> class C extends A with M with N: [ super-resolution.scala:17 ] + | ^ + | -> foo() [ super-resolution.scala:18 ] + | ^^^^^ + | -> override def foo(): Int = b * super.foo() [ super-resolution.scala:15 ] + | ^^^^^^^^^^^ + | -> override def foo(): Int = a + super.foo() [ super-resolution.scala:11 ] + | ^^^^^^^^^^^ + | -> def foo(): Int = m [ super-resolution.scala:7 ] + | ^ +-- Error: tests/init/neg/super-resolution.scala:19:6 ------------------------------------------------------------------- +19 | val a = 10 // error + | ^ + | Access non-initialized value a. Calling trace: + | -> class C extends A with M with N: [ super-resolution.scala:17 ] + | ^ + | -> foo() [ super-resolution.scala:18 ] + | ^^^^^ + | -> override def foo(): Int = b * super.foo() [ super-resolution.scala:15 ] + | ^^^^^^^^^^^ + | -> override def foo(): Int = a + super.foo() [ super-resolution.scala:11 ] + | ^ +-- Error: tests/init/neg/super-resolution.scala:20:6 ------------------------------------------------------------------- +20 | val b = 20 // error + | ^ + | Access non-initialized value b. Calling trace: + | -> class C extends A with M with N: [ super-resolution.scala:17 ] + | ^ + | -> foo() [ super-resolution.scala:18 ] + | ^^^^^ + | -> override def foo(): Int = b * super.foo() [ super-resolution.scala:15 ] + | ^ diff --git a/tests/init/neg/super-resolution.scala b/tests/init/neg/super-resolution.scala new file mode 100644 index 000000000000..d2674bc597e1 --- /dev/null +++ b/tests/init/neg/super-resolution.scala @@ -0,0 +1,23 @@ +abstract class A: + val n: Int + def foo(): Int = n + +trait B: + val m: Int + def foo(): Int = m + +trait M extends A with B: + val a: Int + override def foo(): Int = a + super.foo() + +trait N extends A with B: + val b: Int + override def foo(): Int = b * super.foo() + +class C extends A with M with N: + foo() + val a = 10 // error + val b = 20 // error + val m = 30 // error + val n = 40 + diff --git a/tests/init/neg/super-resolution2.check b/tests/init/neg/super-resolution2.check new file mode 100644 index 000000000000..f852c519e922 --- /dev/null +++ b/tests/init/neg/super-resolution2.check @@ -0,0 +1,28 @@ +-- Error: tests/init/neg/super-resolution2.scala:19:6 ------------------------------------------------------------------ +19 | val n = 40 // error + | ^ + | Access non-initialized value n. Calling trace: + | -> class N extends A with B: [ super-resolution2.scala:9 ] + | ^ + | -> new Inner [ super-resolution2.scala:16 ] + | ^^^^^^^^^ + | -> class Inner: [ super-resolution2.scala:12 ] + | ^ + | -> N.super[A].foo() [ super-resolution2.scala:13 ] + | ^^^^^^^^^^^^^^^^ + | -> def foo(): Int = n [ super-resolution2.scala:3 ] + | ^ +-- Error: tests/init/neg/super-resolution2.scala:18:6 ------------------------------------------------------------------ +18 | val m = 30 // error + | ^ + | Access non-initialized value m. Calling trace: + | -> class N extends A with B: [ super-resolution2.scala:9 ] + | ^ + | -> new Inner [ super-resolution2.scala:16 ] + | ^^^^^^^^^ + | -> class Inner: [ super-resolution2.scala:12 ] + | ^ + | -> N.super.foo() [ super-resolution2.scala:14 ] + | ^^^^^^^^^^^^^ + | -> def foo(): Int = m [ super-resolution2.scala:7 ] + | ^ diff --git a/tests/init/neg/super-resolution2.scala b/tests/init/neg/super-resolution2.scala new file mode 100644 index 000000000000..283fb25a467d --- /dev/null +++ b/tests/init/neg/super-resolution2.scala @@ -0,0 +1,20 @@ +abstract class A: + val n: Int + def foo(): Int = n + +trait B: + val m: Int + def foo(): Int = m + +class N extends A with B: + override def foo(): Int = a * super.foo() + + class Inner: + N.super[A].foo() + N.super.foo() + + new Inner + + val m = 30 // error + val n = 40 // error + val a = 50