diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2012-12-13 17:21:28 -0800 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2012-12-13 17:21:28 -0800 |
commit | 31518ee0cbd10fb0eabcf145df47a764d0f9a96b (patch) | |
tree | 08666abb842e5ac3fb916a79ff653bcc528d7b8f | |
parent | eda88c84daae182266565d21b31ad3c93d9b3be5 (diff) | |
parent | af03afba2596c3c3edfbf7b2a1d128a1d2fc412b (diff) | |
download | scala-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.scala | 10 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala | 32 | ||||
-rw-r--r-- | test/files/run/t6536.check | 27 | ||||
-rw-r--r-- | test/files/run/t6536.scala | 297 |
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 |