summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@typesafe.com>2012-12-13 17:21:28 -0800
committerAdriaan Moors <adriaan.moors@typesafe.com>2012-12-13 17:21:28 -0800
commit31518ee0cbd10fb0eabcf145df47a764d0f9a96b (patch)
tree08666abb842e5ac3fb916a79ff653bcc528d7b8f
parenteda88c84daae182266565d21b31ad3c93d9b3be5 (diff)
parentaf03afba2596c3c3edfbf7b2a1d128a1d2fc412b (diff)
downloadscala-31518ee0cbd10fb0eabcf145df47a764d0f9a96b.tar.gz
scala-31518ee0cbd10fb0eabcf145df47a764d0f9a96b.tar.bz2
scala-31518ee0cbd10fb0eabcf145df47a764d0f9a96b.zip
Merge pull request #1770 from JamesIry/SI-6536_2.9.x
SI-6536 Generates super accessors X.super[Y].blah when Y is a class
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala10
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala32
-rw-r--r--test/files/run/t6536.check27
-rw-r--r--test/files/run/t6536.scala297
5 files changed, 362 insertions, 6 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index d9e8a791af..1f391f5b55 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -767,11 +767,15 @@ abstract class GenICode extends SubComponent {
// to call super constructors explicitly and/or use their 'returned' value.
// therefore, we can ignore this fact, and generate code that leaves nothing
// on the stack (contrary to what the type in the AST says).
- case Apply(fun @ Select(Super(_, mix), _), args) =>
+ case Apply(fun @ Select(Super(qual, mix), _), args) =>
+
+ if (!qual.isInstanceOf[This]) {
+ log("WARNING: super call where selector isn't 'this'. May generate invalid bytecode. Previous phases should have transformed away this form of super.")
+ }
if (settings.debug.value)
- log("Call to super: " + tree);
+ log("Call to super: " + tree)
+
val invokeStyle = SuperCall(mix)
-// if (fun.symbol.isConstructor) Static(true) else SuperCall(mix);
ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos)
val ctx1 = genLoadArguments(args, fun.symbol.info.paramTypes, ctx)
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 921b242555..099503e685 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -1375,7 +1375,7 @@ abstract class RefChecks extends InfoTransform {
def checkSuper(mix: Name) =
// term should have been eliminated by super accessors
- assert(!(qual.symbol.isTrait && sym.isTerm && mix == tpnme.EMPTY))
+ assert(!(qual.symbol.isTrait && sym.isTerm && mix == tpnme.EMPTY), "The following selector should have been transformed by SuperAccessors:" + tree)
transformCaseApply(tree,
qual match {
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 74e246e910..94a6ce3c51 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -118,8 +118,36 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
unit.error(sel.pos, ""+sym.fullLocationString+" is accessed from super. It may not be abstract "+
"unless it is overridden by a member declared `abstract' and `override'");
}
- if (name.isTermName && mix == tpnme.EMPTY && (clazz.isTrait || clazz != currentClass || !validCurrentOwner))
- ensureAccessor(sel)
+
+ // determine if the mix in clazz.super[mix].name is a trait
+ def mixTpeIsTrait = sup.tpe match {
+ case SuperType(_, mixTpe) => mixTpe.typeSymbol.isTrait
+ case _ =>
+ log("Warning: could not determine the type of mix " + mix + " by going through a Super node's "+
+ "type because instead of a SuperType it was " + sup.tpe)
+ false
+ }
+
+ // we need an accessor to get to a super on an outer thing, but only if we can't call name more directly on
+ // a trait implementation class. So this complicated condition is leaving alone cases where we don't need to do
+ // anything special (i.e. we're getting a direct super class) or where a later transform will inject a call to
+ // a trait implementation method directly.
+ //
+ // SI-6536 has more discussion about how this works.
+ //
+ // So, we're looking for items of the form clazz.super[mix].name (or clazz.super.name wich is seen as
+ // clazz.super[EMPTY].name with some limitations. First, name has to be a term rather than a type.
+ // Then there are a couple of cases.
+ def requiresAccessor = name.isTermName && (mix match {
+ // If mix is empty then we only need an accessor if clazz is a trait, it's not this current class,
+ // or the validCurentOwner setting is false...which...ugh, is a mess.
+ case tpnme.EMPTY => clazz.isTrait || clazz != currentClass || !validCurrentOwner
+ // If the mix is set then if it refers to a class and the clazz part isn't the current class
+ // it's not just super[mix].name then we need to generate an accessor.
+ case _ => clazz != currentClass && !mixTpeIsTrait
+ })
+
+ if (requiresAccessor) ensureAccessor(sel)
else sel
}
diff --git a/test/files/run/t6536.check b/test/files/run/t6536.check
new file mode 100644
index 0000000000..8d6b1abec1
--- /dev/null
+++ b/test/files/run/t6536.check
@@ -0,0 +1,27 @@
+a1 a2 a3_t o1/o1 o2 outertrait.Outer/o1 List(a1, o1)
+a1 a2 a3_c o1/o1 o2 outertrait.Outer/o1 List(a1, o1)
+a1 a2 a3_o o1/o1 o2 outertrait.Outer/o1 List(a1, o1)
+a1 a2 a3_tc o1/o1 o2 outertrait.Outer/o1 List(a1, o1)
+a1 a2 a3_to o1/o1 o2 outertrait.Outer/o1 List(a1, o1)
+a1 a2 a3_tco o1/o1 o2 outertrait.Outer/o1 List(a1, o1)
+
+a1 a2 a3_t o1/o1 o2 outerclass.Outer/o1 List(a1, o1)
+a1 a2 a3_c o1/o1 o2 outerclass.Outer/o1 List(a1, o1)
+a1 a2 a3_o o1/o1 o2 outerclass.Outer/o1 List(a1, o1)
+a1 a2 a3_tc o1/o1 o2 outerclass.Outer/o1 List(a1, o1)
+a1 a2 a3_to o1/o1 o2 outerclass.Outer/o1 List(a1, o1)
+a1 a2 a3_tco o1/o1 o2 outerclass.Outer/o1 List(a1, o1)
+
+a1 a2 a3_t o1/o1 o2 withinmethod.Outer/o1 List(a1, o1)
+a1 a2 a3_c o1/o1 o2 withinmethod.Outer/o1 List(a1, o1)
+a1 a2 a3_o o1/o1 o2 withinmethod.Outer/o1 List(a1, o1)
+a1 a2 a3_tc o1/o1 o2 withinmethod.Outer/o1 List(a1, o1)
+a1 a2 a3_to o1/o1 o2 withinmethod.Outer/o1 List(a1, o1)
+a1 a2 a3_tco o1/o1 o2 withinmethod.Outer/o1 List(a1, o1)
+child super class
+child super trait
+child super class 2
+child super trait 2
+child super class 3
+child super trait 3a
+child super trait 3a
diff --git a/test/files/run/t6536.scala b/test/files/run/t6536.scala
new file mode 100644
index 0000000000..397894e4ba
--- /dev/null
+++ b/test/files/run/t6536.scala
@@ -0,0 +1,297 @@
+
+// this was what was broken
+class AClass {
+ def a = "super class"
+}
+class BClass extends AClass {
+ class M {
+ def z = "child " + BClass.super[AClass].a
+ }
+ override def a = ""
+}
+
+// this variant would crash the compiler
+class O3 { def f = "" } // O3 must be a class
+class O4 extends O3 {
+ class T1 { def g = O4.super[O3].f } // ok
+ trait T2 { def g = O4.super[O3].f } // crash
+}
+
+// make sure the fix didn't break this case, which wasn't broken
+trait ATrait {
+ def a = "super trait"
+}
+class BTrait extends ATrait {
+ class M {
+ def z = "child " + BTrait.super[ATrait].a
+ }
+ override def a = ""
+}
+
+// make sure the fix didn't break the simplest case
+class AClass2 {
+ def a = "super class 2"
+}
+class BClass2 extends AClass2 {
+ override def a = ""
+ def z = "child " + super.a
+}
+
+// make sure the fix didn't break this simplest case
+class ATrait2 {
+ def a = "super trait 2"
+}
+class BTrait2 extends ATrait2 {
+ override def a = ""
+ def z = "child " + super.a
+}
+
+// a more interesting example of the all that
+// this was what was broken
+class AClass3 {
+ def a = "super class 3"
+}
+trait ATrait3a {
+ def a = "super trait 3a"
+}
+trait ATrait3b {
+ def a = "super trait 3b"
+}
+class BClass3 extends AClass3 with ATrait3a with ATrait3b {
+ class M {
+ def zclass = "child " + BClass3.super[AClass3].a
+ def ztraita = "child " + BClass3.super[ATrait3a].a
+ def ztraitb = "child " + BClass3.super[ATrait3a].a
+ }
+ override def a = ""
+}
+
+// here's a case where we call super from a trait
+trait Root {
+ def a = "root"
+}
+
+trait Mid extends Root {
+ override def a = "mid"
+ def b = super.a
+}
+
+class Bottom extends Mid
+
+// and this is a bunch of other stuff we want to make sure doesn't explode
+trait A1 { def m1 = "a1" }
+trait A2 { def m1 = "a2" }
+
+trait O1 { def m2 = "o1" ; def o1 = "o1" }
+trait O2 { def m2 = "o2" }
+
+class C1 { def m3 = "c1" }
+trait C2 { def m3 = "c2" }
+
+package outertrait {
+ trait Outer extends O1 with O2 {
+ override def m2 = "outertrait.Outer"
+
+ trait A3_T extends A1 with A2 {
+ override def m1 = "a3_t"
+
+ def f1 = super[A1].m1
+ def f2 = super[A2].m1
+ def f3 = m1
+ def f4 = Outer.super[O1].m2 + "/" + Outer.super[O1].o1
+ def f5 = Outer.super[O2].m2
+ def f6 = Outer.this.m2 + "/" + Outer.this.o1
+ def f7 = () => List(super[A1].m1, Outer.super[O1].m2)
+ }
+
+ class A3_C extends A1 with A2 {
+ override def m1 = "a3_c"
+
+ def f1 = super[A1].m1
+ def f2 = super[A2].m1
+ def f3 = m1
+ def f4 = Outer.super[O1].m2 + "/" + Outer.super[O1].o1
+ def f5 = Outer.super[O2].m2
+ def f6 = Outer.this.m2 + "/" + Outer.this.o1
+ def f7 = () => List(super[A1].m1, Outer.super[O1].m2)
+ }
+
+ object A3_O extends A1 with A2 {
+ override def m1 = "a3_o"
+
+ def f1 = super[A1].m1
+ def f2 = super[A2].m1
+ def f3 = m1
+ def f4 = Outer.super[O1].m2 + "/" + Outer.super[O1].o1
+ def f5 = Outer.super[O2].m2
+ def f6 = Outer.this.m2 + "/" + Outer.this.o1
+ def f7 = () => List(super[A1].m1, Outer.super[O1].m2)
+ }
+
+ class A3_TC extends A3_T { override def m1 = "a3_tc" }
+ object A3_TO extends A3_T { override def m1 = "a3_to" }
+ object A3_TCO extends A3_TC { override def m1 = "a3_tco" }
+ }
+}
+
+package outerclass {
+ class Outer extends O1 with O2 {
+ override def m2 = "outerclass.Outer"
+
+ trait A3_T extends A1 with A2 {
+ override def m1 = "a3_t"
+
+ def f1 = super[A1].m1
+ def f2 = super[A2].m1
+ def f3 = m1
+ def f4 = Outer.super[O1].m2 + "/" + Outer.super[O1].o1
+ def f5 = Outer.super[O2].m2
+ def f6 = Outer.this.m2 + "/" + Outer.this.o1
+ def f7 = () => List(super[A1].m1, Outer.super[O1].m2)
+ }
+
+ class A3_C extends A1 with A2 {
+ override def m1 = "a3_c"
+
+ def f1 = super[A1].m1
+ def f2 = super[A2].m1
+ def f3 = m1
+ def f4 = Outer.super[O1].m2 + "/" + Outer.super[O1].o1
+ def f5 = Outer.super[O2].m2
+ def f6 = Outer.this.m2 + "/" + Outer.this.o1
+ def f7 = () => List(super[A1].m1, Outer.super[O1].m2)
+ }
+
+ object A3_O extends A1 with A2 {
+ override def m1 = "a3_o"
+
+ def f1 = super[A1].m1
+ def f2 = super[A2].m1
+ def f3 = m1
+ def f4 = Outer.super[O1].m2 + "/" + Outer.super[O1].o1
+ def f5 = Outer.super[O2].m2
+ def f6 = Outer.this.m2 + "/" + Outer.this.o1
+ def f7 = () => List(super[A1].m1, Outer.super[O1].m2)
+ }
+
+ class A3_TC extends A3_T { override def m1 = "a3_tc" }
+ object A3_TO extends A3_T { override def m1 = "a3_to" }
+ object A3_TCO extends A3_TC { override def m1 = "a3_tco" }
+ }
+}
+
+package withinmethod {
+ trait Outer extends O1 with O2 {
+ override def m2 = "withinmethod.Outer"
+
+ def method1 = {
+ trait A3_T extends A1 with A2 {
+ override def m1 = "a3_t"
+
+ def f1 = super[A1].m1
+ def f2 = super[A2].m1
+ def f3 = m1
+ def f4 = Outer.super[O1].m2 + "/" + Outer.super[O1].o1
+ def f5 = Outer.super[O2].m2
+ def f6 = Outer.this.m2 + "/" + Outer.this.o1
+ def f7 = () => List(super[A1].m1, Outer.super[O1].m2)
+ }
+ class A3_C extends A1 with A2 {
+ override def m1 = "a3_c"
+
+ def f1 = super[A1].m1
+ def f2 = super[A2].m1
+ def f3 = m1
+ def f4 = Outer.super[O1].m2 + "/" + Outer.super[O1].o1
+ def f5 = Outer.super[O2].m2
+ def f6 = Outer.this.m2 + "/" + Outer.this.o1
+ def f7 = () => List(super[A1].m1, Outer.super[O1].m2)
+ }
+ object A3_O extends A1 with A2 {
+ override def m1 = "a3_o"
+
+ def f1 = super[A1].m1
+ def f2 = super[A2].m1
+ def f3 = m1
+ def f4 = Outer.super[O1].m2 + "/" + Outer.super[O1].o1
+ def f5 = Outer.super[O2].m2
+ def f6 = Outer.this.m2 + "/" + Outer.this.o1
+ def f7 = () => List(super[A1].m1, Outer.super[O1].m2)
+ }
+ class A3_TC extends A3_T { override def m1 = "a3_tc" }
+ object A3_TO extends A3_T { override def m1 = "a3_to" }
+ object A3_TCO extends A3_TC { override def m1 = "a3_tco" }
+
+ List[Test.Anything](new A3_T { }, new A3_C, A3_O, new A3_TC, A3_TO, A3_TCO)
+ }
+ }
+}
+
+object Test {
+ type Anything = {
+ def f1: Any
+ def f2: Any
+ def f3: Any
+ def f4: Any
+ def f5: Any
+ def f6: Any
+ def f7: () => Any
+ }
+
+ def show(x: Anything) {
+ import x._
+ println(List(f1, f2, f3, f4, f5, f6, f7()) mkString " ")
+ }
+ def main(args: Array[String]): Unit = {
+ {
+ val o1 = new outertrait.Outer { }
+ show(new o1.A3_T { })
+ show(new o1.A3_C)
+ show(o1.A3_O)
+ show(new o1.A3_TC)
+ show(o1.A3_TO)
+ show(o1.A3_TCO)
+ println("")
+ }
+
+ {
+ val o1 = new outerclass.Outer { }
+ show(new o1.A3_T { })
+ show(new o1.A3_C)
+ show(o1.A3_O)
+ show(new o1.A3_TC)
+ show(o1.A3_TO)
+ show(o1.A3_TCO)
+ println("")
+ }
+
+ {
+ val o1 = new withinmethod.Outer { }
+ o1.method1 foreach show
+ }
+
+ val bclass = new BClass
+ val bclassm = new bclass.M
+ println(bclassm.z)
+
+ val btrait = new BTrait
+ val btraitm = new btrait.M
+ println(btraitm.z)
+
+ val bclass2 = new BClass2
+ println(bclass2.z)
+
+ val btrait2 = new BTrait2
+ println(btrait2.z)
+
+ val bclass3 = new BClass3
+ val bclass3m = new bclass3.M
+ println(bclass3m.zclass)
+ println(bclass3m.ztraita)
+ println(bclass3m.ztraitb)
+
+ val bottom = new Bottom
+ bottom.a
+ bottom.b
+ }
+} \ No newline at end of file