Closed scabug closed 13 years ago
Imported From: https://issues.scala-lang.org/browse/SI-3004?orig=1 Reporter: benjackman
benjackman said: BTW as a work-around I turned the val hashPrecision into a def hashPrecision in both the trait and the concrete class and the byte-code verifies.
benjackman said: Also here is the -Xprint for the phase before (flatten) and the phase when (mixin) the setter is added: flatten:
[[syntax trees at end of flatten]]// Scala source: Foo.scala
package bizz {
abstract trait DecXTMaker extends java.lang.Object {
def mkA(ctorData: Long): bizz.DecXT;
<stable> <accessor> def hashPrecision(): Int
};
abstract trait DecXTFactory extends java.lang.Object with bizz.DecXTMaker;
abstract class DecXT extends java.lang.Object with bizz.DecXTFactory with ScalaObject {
<paramaccessor> private[this] val raw: Long = _;
<stable> <accessor> <paramaccessor> def raw(): Long = DecXT.this.raw;
def this(raw: Long): bizz.DecXT = {
DecXT.this.raw = raw;
DecXT.super.this();
()
}
};
abstract trait DecXMaker extends java.lang.Object with bizz.DecXTMaker with ScalaObject {
override def mkA(ctorData: Long): bizz.DecX;
override <stable> <accessor> def hashPrecision(): Int
};
final class DecX extends java.lang.Object with bizz.DecXTFactory with bizz.DecXMaker with ScalaObject {
override <bridge> def mkA(ctorData: Long): bizz.DecXT = DecX.this.mkA(ctorData);
def this(): object bizz.DecX = {
DecX.super.this();
DecX.this.$$asInstanceOf[bizz.DecXMaker$$class]()./*DecXMaker$$class*/$$init$$();
()
}
};
class DecX extends bizz.DecXT with bizz.DecXMaker with ScalaObject {
override <bridge> def mkA(ctorData: Long): bizz.DecXT = DecX.this.mkA(ctorData);
def this(raw: Long): bizz.DecX = {
DecX.super.this(raw);
DecX.this.$$asInstanceOf[bizz.DecXMaker$$class]()./*DecXMaker$$class*/$$init$$();
()
}
};
abstract trait DecXMaker$$class extends java.lang.Object with bizz.DecXTMaker with ScalaObject with bizz.DecXMaker {
override def mkA(ctorData: Long): bizz.DecX = new bizz.DecX(ctorData);
private[this] val hashPrecision: Int = _;
override <stable> <accessor> def hashPrecision(): Int = DecXMaker$$class.this.hashPrecision;
def /*DecXMaker$$class*/$$init$$(): Unit = {
DecXMaker$$class.this.hashPrecision = 9;
()
}
}
}
mixin:
[[syntax trees at end of mixin]]// Scala source: Foo.scala
package bizz {
abstract trait DecXTMaker extends java.lang.Object {
def mkA(ctorData: Long): bizz.DecXT;
<stable> <accessor> def hashPrecision(): Int
};
abstract trait DecXTFactory extends java.lang.Object with bizz.DecXTMaker;
abstract class DecXT extends java.lang.Object with bizz.DecXTFactory with ScalaObject {
<paramaccessor> private[this] val raw: Long = _;
<stable> <accessor> <paramaccessor> def raw(): Long = DecXT.this.raw;
def this(raw: Long): bizz.DecXT = {
DecXT.this.raw = raw;
DecXT.super.this();
()
}
};
abstract trait DecXMaker extends java.lang.Object with bizz.DecXTMaker with ScalaObject {
<accessor> def bizz$$DecXMaker$$_setter_#Precision_=(x$$1: Int): Unit;
override def mkA(ctorData: Long): bizz.DecX;
override <stable> <accessor> def hashPrecision(): Int
};
final class DecX extends java.lang.Object with bizz.DecXTFactory with bizz.DecXMaker with ScalaObject {
override <stable> <accessor> def hashPrecision(): Int = DecX.this.hashPrecision;
private[this] val hashPrecision: Int = _;
<accessor> def bizz$$DecXMaker$$_setter_#Precision_=(x$$1: Int): Unit = DecX.this.hashPrecision = x$$1;
override def mkA(ctorData: Long): bizz.DecX = bizz.DecXMaker$$class.mkA(DecX.this, ctorData);
override <bridge> def mkA(ctorData: Long): bizz.DecXT = DecX.this.mkA(ctorData);
def this(): object bizz.DecX = {
DecX.super.this();
bizz.DecXMaker$$class./*DecXMaker$$class*/$$init$$(DecX.this);
()
}
};
class DecX extends bizz.DecXT with bizz.DecXMaker with ScalaObject {
override <stable> <accessor> def hashPrecision(): Int = DecX.this.hashPrecision;
private[this] val hashPrecision: Int = _;
<accessor> def bizz$$DecXMaker$$_setter_#Precision_=(x$$1: Int): Unit = DecX.this.hashPrecision = x$$1;
override def mkA(ctorData: Long): bizz.DecX = bizz.DecXMaker$$class.mkA(DecX.this, ctorData);
override <bridge> def mkA(ctorData: Long): bizz.DecXT = DecX.this.mkA(ctorData);
def this(raw: Long): bizz.DecX = {
DecX.super.this(raw);
bizz.DecXMaker$$class./*DecXMaker$$class*/$$init$$(DecX.this);
()
}
};
abstract trait DecXMaker$$class extends {
override def mkA($$this: bizz.DecXMaker, ctorData: Long): bizz.DecX = new bizz.DecX(ctorData);
def /*DecXMaker$$class*/$$init$$($$this: bizz.DecXMaker): Unit = {
$$this.bizz$$DecXMaker$$_setter_#Precision_=(9);
()
}
}
}
@paulp said: You have revealed great inadequacy in the fix for #1804. I will check in a better fix shortly. (It will still be inadequate, but less so.)
@paulp said: This is fixed, for certain definitions thereof, in r20738.
To answer one of your questions, the static method is a forwarder: for any given object Foo$$ static forwarders are added to companion class Foo except when there are conflicts. The conflict logic is rather hairy. When a companion pair each inherit from the same parent, obviously a forwarder should not be generated for any methods inherited from that parent, but the name manglings and renamings (and the fact that I've had to figure everything out as I go) make correctness a slippery weasel.
benjackman said: Nice work Paul, thanks for the quick fix and explanation. I noticed that in r20738 in the comment you mentioned ticket #3003 I am not sure if that was a typo or not. Cheers.
andrei oprisan (aoprisan) said: It seems this problem is still present in 2.8.0-rc1 . The code that triggers it: {code} object MyClass { val duplicate: Int = 10 }
class MyClass { private val duplicate = MyClass.duplicate } {code}[[BR]]
Whenever an instance of MyClass is created, the following exception is thrown: {code} Exception in thread "main" java.lang.ClassFormatError: Duplicate method name&signature in class file duplicatemerthodsignaturescala/MyClass {code}[[BR]]
Javap output: {code} public class duplicatemerthodsignaturescala.MyClass extends java.lang.Object implements scala.ScalaObject{ private final int duplicate; public static final int duplicate(); private int duplicate(); public duplicatemerthodsignaturescala.MyClass(); } {code}[[BR]]
JVM version: 1.6.0_18; Scala version: 2.8.0.RC1; OS: Ubuntu 9.10.
andrei oprisan (aoprisan) said: I apologize for reposting the same thing, but the first time I did a mistake in the formatting :( and I couldn't edit the original comment.
It seems this problem is still present in 2.8.0-rc1 . The code that triggers it:
object MyClass {
val duplicate: Int = 10
}
class MyClass {
private val duplicate = MyClass.duplicate
}
Whenever an instance of !MyClass is created, the following exception is thrown:
Exception in thread "main" java.lang.ClassFormatError: Duplicate method name&signature in class file duplicatemerthodsignaturescala/MyClass
Javap output:
public class duplicatemerthodsignaturescala.MyClass extends java.lang.Object implements scala.ScalaObject{
private final int duplicate;
public static final int duplicate();
private int duplicate();
public duplicatemerthodsignaturescala.MyClass();
}
JVM version: 1.6.0_18; Scala version: 2.8.0.RC1; OS: Ubuntu 9.10.
@paulp said: (In r21611) Fix and test case for forwarder duplicate bug. Closes #3004, no review.
Ignoring the terribleness of the design of this class hierarchy, I am seeing invalid byte-code problems with 2.8.Beta1 that I didn't see in 2.7.7 land:
here is the file that causes the issue:
Here is the javap output for the DecX class scalac generates:
Finally here the exception i get in java land
Curiously enough it if placed in the root package (aka no package name given) the bytecode generated looks like this instead!
and the console works
finally just make life a little easier here is the old 2.7.7 javap's first, with no package name
secondly, in the bizz package (looks the same as 2.7.7 no package to me)
out of curiosity why is a setter method being generated for a val? ( i don't know all that much about how the stuff ends up compiling) & where is that static one coming from?