bug
bug copied to clipboard
final val overriding def: Duplicate method name
reproduction steps
using Scala 2.13.4, example:
case object Foo extends Product {
override final val productPrefix = "Foo"
}
println(Foo)
problem
Causes a runtime error in the class loader:
java.lang.ClassFormatError: Duplicate method name "productPrefix" with signature "()Ljava.lang.String;" in class file Playground$Foo$
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
at sbt.internal.ManagedClassLoader.findClass(ManagedClassLoader.java:98)
at sbt.internal.BottomClassLoader.lambda$findClass$0(BottomClassLoader.java:56)
at sbt.internal.ClassLoadingLock.withLock(ClassLoadingLock.java:28)
at sbt.internal.BottomClassLoader.findClass(BottomClassLoader.java:51)
at sbt.internal.BottomClassLoader.loadClass(BottomClassLoader.java:66)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at Playground$.delayedEndpoint$Playground$1(main.scala:7)
...
Possibly related: #8663
Bytecode diff:
diff --git Foo$.class Foo$.class
index 2928276..9c1b63a 100644
--- Foo$.class
+++ Foo$.class
@@ -1,26 +1,27 @@
public final class Foo$ implements scala.Product,java.io.Serializable {
public static final Foo$ MODULE$;
descriptor: LFoo$;
- private static final java.lang.String productPrefix;
- descriptor: Ljava/lang/String;
-
public static {};
descriptor: ()V
Code:
##: new ### // class Foo$
##: dup
##: invokespecial ### // Method "<init>":()V
##: putstatic ### // Field MODULE$:LFoo$;
##: getstatic ### // Field MODULE$:LFoo$;
##: invokestatic ### // InterfaceMethod scala/Product.$init$:(Lscala/Product;)V
-##: ldc ### // String Foo
-##: putstatic ### // Field productPrefix:Ljava/lang/String;
##: return
+ public java.lang.String productPrefix();
+ descriptor: ()Ljava/lang/String;
+ Code:
+##: invokestatic ### // InterfaceMethod scala/Product.productPrefix$:(Lscala/Product;)Ljava/lang/String;
+##: areturn
+
public java.lang.String productElementName(int);
descriptor: (I)Ljava/lang/String;
Code:
##: iload_1
##: invokestatic ### // InterfaceMethod scala/Product.productElementName$:(Lscala/Product;I)Ljava/lang/String;
@@ -30,14 +31,14 @@ public final class Foo$ implements scala.Product,java.io.Serializable {
descriptor: ()Lscala/collection/Iterator;
Code:
##: invokestatic ### // InterfaceMethod scala/Product.productElementNames$:(Lscala/Product;)Lscala/collection/Iterator;
##: areturn
- public java.lang.String productPrefix();
+ public final java.lang.String productPrefix();
descriptor: ()Ljava/lang/String;
Code:
-##: getstatic ### // Field productPrefix:Ljava/lang/String;
+##: ldc ### // String Foo
##: areturn
public int productArity();
descriptor: ()I
Code:
The static field and initialising it disappears and productPrefix has the string inlined, but then there's also the erroneous duplicate method.
Also broken in 2.12.12 and 2.11.12, works in 2.10.7.
(note that extends Product is redundant, so that can be removed from the minimization)
works in Scala 3, which has me wondering if the cause is actually before the back end
An attempt was made in scala/scala#9431.
Workaround: add a type annotation
case object Foo extends Product {
- override final val productPrefix = "Foo"
+ override final val productPrefix: String = "Foo"
}
println(Foo)
I just ran into this error while changing some code. If it helps identify the root cause, it seems to only happen when the subclass is a class or an object -- traits don't trigger the error.
class: https://scastie.scala-lang.org/z8frNWiOTFSM26xn8klbYQ
object: https://scastie.scala-lang.org/V3JyKzSaSEWx1KH78sFWyQ
trait: https://scastie.scala-lang.org/K6BUfbaaQ9mp92jA6NMeNA
An attempt was made
A valiant attempt.
Thanks @mrdziuban I'll take a look at my lame attempt. I see lrytz left me lots of hints to follow up on.
That attempt says "Quick lunchtime fix." but it was also while company was having a security problem, very stressful period, finally they decided to move overseas. In retrospect, one wonders what was the best use of one's time.
Workaround is to use 2.10.7.
Note that it happens with any method with result type that is a constant value but not AnyVal, including a Java enum. I'll take another look at the intersection of detecting matching members in mixin and whether they should survive erasure.
Also under -Xsource:3, you don't have an opportunity to have the constant type inferred!