New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
VerifyError with qualified super #6536
Comments
Imported From: https://issues.scala-lang.org/browse/SI-6536?orig=1 |
@szeiger said: |
@adriaanm said: |
@JamesIry said: public class B$M extends java.lang.Object implements scala.ScalaObject{
public final B $outer;
public java.lang.String z();
Code:
0: new #9; //class scala/collection/mutable/StringBuilder
3: dup
4: invokespecial #13; //Method scala/collection/mutable/StringBuilder."<init>":()V
7: ldc #16; //String child
9: invokevirtual #20; //Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder;
12: aload_0
13: invokespecial #25; //Method A.a:()Ljava/lang/String;
16: invokevirtual #20; //Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder;
19: invokevirtual #28; //Method scala/collection/mutable/StringBuilder.toString:()Ljava/lang/String;
22: areturn
public B B$M$$$outer();
Code:
0: aload_0
1: getfield #34; //Field $outer:LB;
4: areturn
public B$M(B);
Code:
0: aload_1
1: ifnonnull 12
4: new #37; //class java/lang/NullPointerException
7: dup
8: invokespecial #38; //Method java/lang/NullPointerException."<init>":()V
11: athrow
12: aload_0
13: aload_1
14: putfield #34; //Field $outer:LB;
17: aload_0
18: invokespecial #41; //Method java/lang/Object."<init>":()V
21: return
} |
@JamesIry said: 12: aload_0
13: invokespecial #25; //Method A.a:()Ljava/lang/String; would be correct if z were defined directly on B. But the intervening class M means it should be going through the M instance's outer field to get to the enclosing B instance first. |
@JamesIry said: class B$M extends java.lang.Object with ScalaObject {
def z(): java.lang.String = "child".+(B$M.this.B$M$$$outer().super[A].a()); But the icode isn't right def z(): java.lang.String {
locals:
startBlock: 1
blocks: [1]
1:
6 CALL_PRIMITIVE(StartConcat)
6 CONSTANT("child")
6 CALL_PRIMITIVE(StringConcat(REF(class String)))
6 THIS(B$M)
6 CALL_METHOD A.a (super(A))
6 CALL_PRIMITIVE(StringConcat(REF(class String)))
6 CALL_PRIMITIVE(EndConcat)
6 RETURN(REF(class String))
} |
@JamesIry said: case Apply(fun @ Select(Super(_, mix), _), args) => It ignores the tree that's the left argument of Super, assuming it will be a This. |
@JamesIry said: |
@JamesIry said: {code} if (name.isTermName && mix == tpnme.EMPTY && (clazz.isTrait || clazz != currentClass || !validCurrentOwner)) {code} which this call fails because mix is not empty, and thus the tree isn't transformed with an accessor. Changing the condition to {code} if (name.isTermName && ((mix == tpnme.EMPTY && clazz.isTrait) || clazz != currentClass || !validCurrentOwner)) {code} seems to solve this bug and doesn't break the case where A is a trait. However, this is some subtle stuff so I'm digging in to understand exactly what the condition is detecting/preventing. For instance, the name "mix" suggests that it actually SHOULD be empty in this case so maybe the real problem lies upstream. |
@JamesIry said: |
@retronym said: |
@JamesIry said: Changing the condition to the eminently reasonable {code} if (name.isTermName && (clazz.isTrait || !currentClass.isSubClass(clazz) || !validCurrentOwner)) {code} fixes this bug. But it reveals another problem. If you need to do B.super[A].a and B.super[C].a (i.e. you've got a second trait in the mix) then the current name mangler tries to generate the same method name twice - it doesn't take into account the fact that the super accessors go to different things. Fixing that is easy enough but requires a binary breaking change or a giant hack-ball. I'm going to see if I can narrowly fix this bug without creating any more breakage related to name mangling and then separately fix the name mangling in master where the binary incompatibility is okay. If not we may have to defer this bug. |
@JamesIry said (edited on Dec 13, 2012 5:17:26 AM UTC): |
@paulp said: class O1 { def f = "" } // O1 must be a class
class O2 extends O1 {
class T1 { def g = O2.super[O1].f } // ok
trait T2 { def g = O2.super[O1].f } // crash
}
/****
class O2$T2$class
at scala.tools.nsc.transform.Mixin$MixinTransformer.scala$tools$nsc$transform$Mixin$MixinTransformer$$postTransform(Mixin.scala:1202)
at scala.tools.nsc.transform.Mixin$MixinTransformer$$anonfun$transform$1.apply(Mixin.scala:1248)
at scala.tools.nsc.transform.Mixin$MixinTransformer$$anonfun$transform$1.apply(Mixin.scala:1248)
at scala.reflect.internal.SymbolTable.atPhase(SymbolTable.scala:201)
****/ |
@JamesIry said: |
@JamesIry said: |
Note, there are two work-arounds that solve this problem. One specific to this bug report and one more general.
The specific one is
That works because this bug is only triggered when there is a type qualifier on a super access to an outer class. Get rid of the type qualifier and it's all good. But it's not fully general if you need to decide among several different sources for 'a'.
The more general work around is to manually do your own accessor
The text was updated successfully, but these errors were encountered: