Skip to content

Commit 31518ee

Browse files
committed
Merge pull request scala#1770 from JamesIry/SI-6536_2.9.x
SI-6536 Generates super accessors X.super[Y].blah when Y is a class
2 parents eda88c8 + af03afb commit 31518ee

File tree

5 files changed

+362
-6
lines changed

5 files changed

+362
-6
lines changed

src/compiler/scala/tools/nsc/backend/icode/GenICode.scala

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -767,11 +767,15 @@ abstract class GenICode extends SubComponent {
767767
// to call super constructors explicitly and/or use their 'returned' value.
768768
// therefore, we can ignore this fact, and generate code that leaves nothing
769769
// on the stack (contrary to what the type in the AST says).
770-
case Apply(fun @ Select(Super(_, mix), _), args) =>
770+
case Apply(fun @ Select(Super(qual, mix), _), args) =>
771+
772+
if (!qual.isInstanceOf[This]) {
773+
log("WARNING: super call where selector isn't 'this'. May generate invalid bytecode. Previous phases should have transformed away this form of super.")
774+
}
771775
if (settings.debug.value)
772-
log("Call to super: " + tree);
776+
log("Call to super: " + tree)
777+
773778
val invokeStyle = SuperCall(mix)
774-
// if (fun.symbol.isConstructor) Static(true) else SuperCall(mix);
775779

776780
ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos)
777781
val ctx1 = genLoadArguments(args, fun.symbol.info.paramTypes, ctx)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1375,7 +1375,7 @@ abstract class RefChecks extends InfoTransform {
13751375

13761376
def checkSuper(mix: Name) =
13771377
// term should have been eliminated by super accessors
1378-
assert(!(qual.symbol.isTrait && sym.isTerm && mix == tpnme.EMPTY))
1378+
assert(!(qual.symbol.isTrait && sym.isTerm && mix == tpnme.EMPTY), "The following selector should have been transformed by SuperAccessors:" + tree)
13791379

13801380
transformCaseApply(tree,
13811381
qual match {

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

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,36 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
118118
unit.error(sel.pos, ""+sym.fullLocationString+" is accessed from super. It may not be abstract "+
119119
"unless it is overridden by a member declared `abstract' and `override'");
120120
}
121-
if (name.isTermName && mix == tpnme.EMPTY && (clazz.isTrait || clazz != currentClass || !validCurrentOwner))
122-
ensureAccessor(sel)
121+
122+
// determine if the mix in clazz.super[mix].name is a trait
123+
def mixTpeIsTrait = sup.tpe match {
124+
case SuperType(_, mixTpe) => mixTpe.typeSymbol.isTrait
125+
case _ =>
126+
log("Warning: could not determine the type of mix " + mix + " by going through a Super node's "+
127+
"type because instead of a SuperType it was " + sup.tpe)
128+
false
129+
}
130+
131+
// we need an accessor to get to a super on an outer thing, but only if we can't call name more directly on
132+
// a trait implementation class. So this complicated condition is leaving alone cases where we don't need to do
133+
// anything special (i.e. we're getting a direct super class) or where a later transform will inject a call to
134+
// a trait implementation method directly.
135+
//
136+
// SI-6536 has more discussion about how this works.
137+
//
138+
// So, we're looking for items of the form clazz.super[mix].name (or clazz.super.name wich is seen as
139+
// clazz.super[EMPTY].name with some limitations. First, name has to be a term rather than a type.
140+
// Then there are a couple of cases.
141+
def requiresAccessor = name.isTermName && (mix match {
142+
// If mix is empty then we only need an accessor if clazz is a trait, it's not this current class,
143+
// or the validCurentOwner setting is false...which...ugh, is a mess.
144+
case tpnme.EMPTY => clazz.isTrait || clazz != currentClass || !validCurrentOwner
145+
// If the mix is set then if it refers to a class and the clazz part isn't the current class
146+
// it's not just super[mix].name then we need to generate an accessor.
147+
case _ => clazz != currentClass && !mixTpeIsTrait
148+
})
149+
150+
if (requiresAccessor) ensureAccessor(sel)
123151
else sel
124152
}
125153

test/files/run/t6536.check

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
a1 a2 a3_t o1/o1 o2 outertrait.Outer/o1 List(a1, o1)
2+
a1 a2 a3_c o1/o1 o2 outertrait.Outer/o1 List(a1, o1)
3+
a1 a2 a3_o o1/o1 o2 outertrait.Outer/o1 List(a1, o1)
4+
a1 a2 a3_tc o1/o1 o2 outertrait.Outer/o1 List(a1, o1)
5+
a1 a2 a3_to o1/o1 o2 outertrait.Outer/o1 List(a1, o1)
6+
a1 a2 a3_tco o1/o1 o2 outertrait.Outer/o1 List(a1, o1)
7+
8+
a1 a2 a3_t o1/o1 o2 outerclass.Outer/o1 List(a1, o1)
9+
a1 a2 a3_c o1/o1 o2 outerclass.Outer/o1 List(a1, o1)
10+
a1 a2 a3_o o1/o1 o2 outerclass.Outer/o1 List(a1, o1)
11+
a1 a2 a3_tc o1/o1 o2 outerclass.Outer/o1 List(a1, o1)
12+
a1 a2 a3_to o1/o1 o2 outerclass.Outer/o1 List(a1, o1)
13+
a1 a2 a3_tco o1/o1 o2 outerclass.Outer/o1 List(a1, o1)
14+
15+
a1 a2 a3_t o1/o1 o2 withinmethod.Outer/o1 List(a1, o1)
16+
a1 a2 a3_c o1/o1 o2 withinmethod.Outer/o1 List(a1, o1)
17+
a1 a2 a3_o o1/o1 o2 withinmethod.Outer/o1 List(a1, o1)
18+
a1 a2 a3_tc o1/o1 o2 withinmethod.Outer/o1 List(a1, o1)
19+
a1 a2 a3_to o1/o1 o2 withinmethod.Outer/o1 List(a1, o1)
20+
a1 a2 a3_tco o1/o1 o2 withinmethod.Outer/o1 List(a1, o1)
21+
child super class
22+
child super trait
23+
child super class 2
24+
child super trait 2
25+
child super class 3
26+
child super trait 3a
27+
child super trait 3a

test/files/run/t6536.scala

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
2+
// this was what was broken
3+
class AClass {
4+
def a = "super class"
5+
}
6+
class BClass extends AClass {
7+
class M {
8+
def z = "child " + BClass.super[AClass].a
9+
}
10+
override def a = ""
11+
}
12+
13+
// this variant would crash the compiler
14+
class O3 { def f = "" } // O3 must be a class
15+
class O4 extends O3 {
16+
class T1 { def g = O4.super[O3].f } // ok
17+
trait T2 { def g = O4.super[O3].f } // crash
18+
}
19+
20+
// make sure the fix didn't break this case, which wasn't broken
21+
trait ATrait {
22+
def a = "super trait"
23+
}
24+
class BTrait extends ATrait {
25+
class M {
26+
def z = "child " + BTrait.super[ATrait].a
27+
}
28+
override def a = ""
29+
}
30+
31+
// make sure the fix didn't break the simplest case
32+
class AClass2 {
33+
def a = "super class 2"
34+
}
35+
class BClass2 extends AClass2 {
36+
override def a = ""
37+
def z = "child " + super.a
38+
}
39+
40+
// make sure the fix didn't break this simplest case
41+
class ATrait2 {
42+
def a = "super trait 2"
43+
}
44+
class BTrait2 extends ATrait2 {
45+
override def a = ""
46+
def z = "child " + super.a
47+
}
48+
49+
// a more interesting example of the all that
50+
// this was what was broken
51+
class AClass3 {
52+
def a = "super class 3"
53+
}
54+
trait ATrait3a {
55+
def a = "super trait 3a"
56+
}
57+
trait ATrait3b {
58+
def a = "super trait 3b"
59+
}
60+
class BClass3 extends AClass3 with ATrait3a with ATrait3b {
61+
class M {
62+
def zclass = "child " + BClass3.super[AClass3].a
63+
def ztraita = "child " + BClass3.super[ATrait3a].a
64+
def ztraitb = "child " + BClass3.super[ATrait3a].a
65+
}
66+
override def a = ""
67+
}
68+
69+
// here's a case where we call super from a trait
70+
trait Root {
71+
def a = "root"
72+
}
73+
74+
trait Mid extends Root {
75+
override def a = "mid"
76+
def b = super.a
77+
}
78+
79+
class Bottom extends Mid
80+
81+
// and this is a bunch of other stuff we want to make sure doesn't explode
82+
trait A1 { def m1 = "a1" }
83+
trait A2 { def m1 = "a2" }
84+
85+
trait O1 { def m2 = "o1" ; def o1 = "o1" }
86+
trait O2 { def m2 = "o2" }
87+
88+
class C1 { def m3 = "c1" }
89+
trait C2 { def m3 = "c2" }
90+
91+
package outertrait {
92+
trait Outer extends O1 with O2 {
93+
override def m2 = "outertrait.Outer"
94+
95+
trait A3_T extends A1 with A2 {
96+
override def m1 = "a3_t"
97+
98+
def f1 = super[A1].m1
99+
def f2 = super[A2].m1
100+
def f3 = m1
101+
def f4 = Outer.super[O1].m2 + "/" + Outer.super[O1].o1
102+
def f5 = Outer.super[O2].m2
103+
def f6 = Outer.this.m2 + "/" + Outer.this.o1
104+
def f7 = () => List(super[A1].m1, Outer.super[O1].m2)
105+
}
106+
107+
class A3_C extends A1 with A2 {
108+
override def m1 = "a3_c"
109+
110+
def f1 = super[A1].m1
111+
def f2 = super[A2].m1
112+
def f3 = m1
113+
def f4 = Outer.super[O1].m2 + "/" + Outer.super[O1].o1
114+
def f5 = Outer.super[O2].m2
115+
def f6 = Outer.this.m2 + "/" + Outer.this.o1
116+
def f7 = () => List(super[A1].m1, Outer.super[O1].m2)
117+
}
118+
119+
object A3_O extends A1 with A2 {
120+
override def m1 = "a3_o"
121+
122+
def f1 = super[A1].m1
123+
def f2 = super[A2].m1
124+
def f3 = m1
125+
def f4 = Outer.super[O1].m2 + "/" + Outer.super[O1].o1
126+
def f5 = Outer.super[O2].m2
127+
def f6 = Outer.this.m2 + "/" + Outer.this.o1
128+
def f7 = () => List(super[A1].m1, Outer.super[O1].m2)
129+
}
130+
131+
class A3_TC extends A3_T { override def m1 = "a3_tc" }
132+
object A3_TO extends A3_T { override def m1 = "a3_to" }
133+
object A3_TCO extends A3_TC { override def m1 = "a3_tco" }
134+
}
135+
}
136+
137+
package outerclass {
138+
class Outer extends O1 with O2 {
139+
override def m2 = "outerclass.Outer"
140+
141+
trait A3_T extends A1 with A2 {
142+
override def m1 = "a3_t"
143+
144+
def f1 = super[A1].m1
145+
def f2 = super[A2].m1
146+
def f3 = m1
147+
def f4 = Outer.super[O1].m2 + "/" + Outer.super[O1].o1
148+
def f5 = Outer.super[O2].m2
149+
def f6 = Outer.this.m2 + "/" + Outer.this.o1
150+
def f7 = () => List(super[A1].m1, Outer.super[O1].m2)
151+
}
152+
153+
class A3_C extends A1 with A2 {
154+
override def m1 = "a3_c"
155+
156+
def f1 = super[A1].m1
157+
def f2 = super[A2].m1
158+
def f3 = m1
159+
def f4 = Outer.super[O1].m2 + "/" + Outer.super[O1].o1
160+
def f5 = Outer.super[O2].m2
161+
def f6 = Outer.this.m2 + "/" + Outer.this.o1
162+
def f7 = () => List(super[A1].m1, Outer.super[O1].m2)
163+
}
164+
165+
object A3_O extends A1 with A2 {
166+
override def m1 = "a3_o"
167+
168+
def f1 = super[A1].m1
169+
def f2 = super[A2].m1
170+
def f3 = m1
171+
def f4 = Outer.super[O1].m2 + "/" + Outer.super[O1].o1
172+
def f5 = Outer.super[O2].m2
173+
def f6 = Outer.this.m2 + "/" + Outer.this.o1
174+
def f7 = () => List(super[A1].m1, Outer.super[O1].m2)
175+
}
176+
177+
class A3_TC extends A3_T { override def m1 = "a3_tc" }
178+
object A3_TO extends A3_T { override def m1 = "a3_to" }
179+
object A3_TCO extends A3_TC { override def m1 = "a3_tco" }
180+
}
181+
}
182+
183+
package withinmethod {
184+
trait Outer extends O1 with O2 {
185+
override def m2 = "withinmethod.Outer"
186+
187+
def method1 = {
188+
trait A3_T extends A1 with A2 {
189+
override def m1 = "a3_t"
190+
191+
def f1 = super[A1].m1
192+
def f2 = super[A2].m1
193+
def f3 = m1
194+
def f4 = Outer.super[O1].m2 + "/" + Outer.super[O1].o1
195+
def f5 = Outer.super[O2].m2
196+
def f6 = Outer.this.m2 + "/" + Outer.this.o1
197+
def f7 = () => List(super[A1].m1, Outer.super[O1].m2)
198+
}
199+
class A3_C extends A1 with A2 {
200+
override def m1 = "a3_c"
201+
202+
def f1 = super[A1].m1
203+
def f2 = super[A2].m1
204+
def f3 = m1
205+
def f4 = Outer.super[O1].m2 + "/" + Outer.super[O1].o1
206+
def f5 = Outer.super[O2].m2
207+
def f6 = Outer.this.m2 + "/" + Outer.this.o1
208+
def f7 = () => List(super[A1].m1, Outer.super[O1].m2)
209+
}
210+
object A3_O extends A1 with A2 {
211+
override def m1 = "a3_o"
212+
213+
def f1 = super[A1].m1
214+
def f2 = super[A2].m1
215+
def f3 = m1
216+
def f4 = Outer.super[O1].m2 + "/" + Outer.super[O1].o1
217+
def f5 = Outer.super[O2].m2
218+
def f6 = Outer.this.m2 + "/" + Outer.this.o1
219+
def f7 = () => List(super[A1].m1, Outer.super[O1].m2)
220+
}
221+
class A3_TC extends A3_T { override def m1 = "a3_tc" }
222+
object A3_TO extends A3_T { override def m1 = "a3_to" }
223+
object A3_TCO extends A3_TC { override def m1 = "a3_tco" }
224+
225+
List[Test.Anything](new A3_T { }, new A3_C, A3_O, new A3_TC, A3_TO, A3_TCO)
226+
}
227+
}
228+
}
229+
230+
object Test {
231+
type Anything = {
232+
def f1: Any
233+
def f2: Any
234+
def f3: Any
235+
def f4: Any
236+
def f5: Any
237+
def f6: Any
238+
def f7: () => Any
239+
}
240+
241+
def show(x: Anything) {
242+
import x._
243+
println(List(f1, f2, f3, f4, f5, f6, f7()) mkString " ")
244+
}
245+
def main(args: Array[String]): Unit = {
246+
{
247+
val o1 = new outertrait.Outer { }
248+
show(new o1.A3_T { })
249+
show(new o1.A3_C)
250+
show(o1.A3_O)
251+
show(new o1.A3_TC)
252+
show(o1.A3_TO)
253+
show(o1.A3_TCO)
254+
println("")
255+
}
256+
257+
{
258+
val o1 = new outerclass.Outer { }
259+
show(new o1.A3_T { })
260+
show(new o1.A3_C)
261+
show(o1.A3_O)
262+
show(new o1.A3_TC)
263+
show(o1.A3_TO)
264+
show(o1.A3_TCO)
265+
println("")
266+
}
267+
268+
{
269+
val o1 = new withinmethod.Outer { }
270+
o1.method1 foreach show
271+
}
272+
273+
val bclass = new BClass
274+
val bclassm = new bclass.M
275+
println(bclassm.z)
276+
277+
val btrait = new BTrait
278+
val btraitm = new btrait.M
279+
println(btraitm.z)
280+
281+
val bclass2 = new BClass2
282+
println(bclass2.z)
283+
284+
val btrait2 = new BTrait2
285+
println(btrait2.z)
286+
287+
val bclass3 = new BClass3
288+
val bclass3m = new bclass3.M
289+
println(bclass3m.zclass)
290+
println(bclass3m.ztraita)
291+
println(bclass3m.ztraitb)
292+
293+
val bottom = new Bottom
294+
bottom.a
295+
bottom.b
296+
}
297+
}

0 commit comments

Comments
 (0)