Skip to content

Commit

Permalink
Merge pull request #15703 from dotty-staging/init-super-accessor
Browse files Browse the repository at this point in the history
Handle super accessors in initialization checker
  • Loading branch information
liufengyun authored Jul 19, 2022
2 parents 67f11ff + f98b23b commit 56e9a93
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 17 deletions.
23 changes: 6 additions & 17 deletions compiler/src/dotty/tools/dotc/transform/init/Semantic.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 != _))

36 changes: 36 additions & 0 deletions tests/init/neg/super-resolution.check
Original file line number Diff line number Diff line change
@@ -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 ]
| ^
23 changes: 23 additions & 0 deletions tests/init/neg/super-resolution.scala
Original file line number Diff line number Diff line change
@@ -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

28 changes: 28 additions & 0 deletions tests/init/neg/super-resolution2.check
Original file line number Diff line number Diff line change
@@ -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 ]
| ^
20 changes: 20 additions & 0 deletions tests/init/neg/super-resolution2.scala
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 56e9a93

Please sign in to comment.