Skip to content

Commit 87ca181

Browse files
committed
Merge pull request scala#3935 from lrytz/t8803
SI-8803 generate super accessor for super[A], if A is outer superclass
2 parents 9753f23 + f324ca5 commit 87ca181

File tree

4 files changed

+90
-5
lines changed

4 files changed

+90
-5
lines changed

src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,11 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
8282
val buf = accDefs.getOrElse(clazz, sys.error("no acc def buf for "+clazz))
8383
buf += typers(clazz) typed tree
8484
}
85-
private def ensureAccessor(sel: Select) = {
85+
private def ensureAccessor(sel: Select, mixName: TermName = nme.EMPTY) = {
8686
val Select(qual, name) = sel
8787
val sym = sel.symbol
8888
val clazz = qual.symbol
89-
val supername = nme.superName(name)
89+
val supername = nme.superName(name, mixName)
9090
val superAcc = clazz.info.decl(supername).suchThat(_.alias == sym) orElse {
9191
debuglog(s"add super acc ${sym.fullLocationString} to $clazz")
9292
val acc = clazz.newMethod(supername, sel.pos, SUPERACCESSOR | PRIVATE | ARTIFACT) setAlias sym
@@ -150,8 +150,20 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
150150
}
151151
}
152152

153-
if (name.isTermName && mix == tpnme.EMPTY && (clazz.isTrait || clazz != currentClass || !validCurrentOwner))
154-
ensureAccessor(sel)
153+
def mixIsTrait = sup.tpe match {
154+
case SuperType(thisTpe, superTpe) => superTpe.typeSymbol.isTrait
155+
}
156+
157+
val needAccessor = name.isTermName && {
158+
mix.isEmpty && (clazz.isTrait || clazz != currentClass || !validCurrentOwner) ||
159+
// SI-8803. If we access super[A] from an inner class (!= currentClass) or closure (validCurrentOwner),
160+
// where A is the superclass we need an accessor. If A is a parent trait we don't: in this case mixin
161+
// will re-route the super call directly to the impl class (it's statically known).
162+
!mix.isEmpty && (clazz != currentClass || !validCurrentOwner) && !mixIsTrait
163+
}
164+
165+
if (needAccessor)
166+
ensureAccessor(sel, mix.toTermName)
155167
else sel
156168
}
157169

src/reflect/scala/reflect/internal/StdNames.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ trait StdNames {
473473
)
474474

475475
def localDummyName(clazz: Symbol): TermName = newTermName(LOCALDUMMY_PREFIX + clazz.name + ">")
476-
def superName(name: Name): TermName = newTermName(SUPER_PREFIX_STRING + name)
476+
def superName(name: Name, mix: Name = EMPTY): TermName = newTermName(SUPER_PREFIX_STRING + name + (if (mix.isEmpty) "" else "$" + mix))
477477

478478
/** The name of an accessor for protected symbols. */
479479
def protName(name: Name): TermName = newTermName(PROTECTED_PREFIX + name)

test/files/run/t8803.check

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
a
2+
b
3+
b
4+
c
5+
a
6+
b
7+
b
8+
c
9+
a
10+
b
11+
b
12+
c
13+
a
14+
b
15+
b
16+
c

test/files/run/t8803.scala

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
class A {
2+
def m = "a"
3+
protected def n = "a"
4+
}
5+
6+
trait B {
7+
def m = "b"
8+
protected def n = "b"
9+
}
10+
11+
class C extends A with B {
12+
override def m = "c"
13+
override protected def n = "c"
14+
15+
val f1 = () => super[A].m
16+
val f2 = () => super[B].m
17+
val f3 = () => super.m
18+
val f4 = () => this.m
19+
20+
val g1 = new runtime.AbstractFunction0[String] { def apply() = C.super[A].m }
21+
val g2 = new runtime.AbstractFunction0[String] { def apply() = C.super[B].m }
22+
val g3 = new runtime.AbstractFunction0[String] { def apply() = C.super.m }
23+
val g4 = new runtime.AbstractFunction0[String] { def apply() = C.this.m }
24+
25+
val h1 = () => super[A].n
26+
val h2 = () => super[B].n
27+
val h3 = () => super.n
28+
val h4 = () => this.n
29+
30+
val i1 = new runtime.AbstractFunction0[String] { def apply() = C.super[A].n }
31+
val i2 = new runtime.AbstractFunction0[String] { def apply() = C.super[B].n }
32+
val i3 = new runtime.AbstractFunction0[String] { def apply() = C.super.n }
33+
val i4 = new runtime.AbstractFunction0[String] { def apply() = C.this.n }
34+
}
35+
36+
object Test extends App {
37+
val c = new C
38+
println(c.f1())
39+
println(c.f2())
40+
println(c.f3())
41+
println(c.f4())
42+
43+
println(c.g1())
44+
println(c.g2())
45+
println(c.g3())
46+
println(c.g4())
47+
48+
println(c.h1())
49+
println(c.h2())
50+
println(c.h3())
51+
println(c.h4())
52+
53+
println(c.i1())
54+
println(c.i2())
55+
println(c.i3())
56+
println(c.i4())
57+
}

0 commit comments

Comments
 (0)