Closed scabug closed 6 years ago
Imported From: https://issues.scala-lang.org/browse/SI-1459?orig=1 Reporter: Harri Kulmala (hkulmala) Attachments:
Harri Kulmala (hkulmala) said: Updated package to reproduce the problem.
Anders Bach Nielsen [X] (nielsen) said: Error is verifies with the current compiler from trunk
Reuben (catdogboy) said (edited by @paulp on Feb 21, 2013 10:15:23 PM UTC): I ran into this bug too. Here's another simple example implementing a java interface with a varargs method, then unable to resolve the virtual method:
runBug:
[java] Exception in thread "main" java.lang.AbstractMethodError: bug.Bugger.whatever(Ljava/lang/String;[Ljava/lang/String;)V
[java] at bug.BugRunner$.doWhatever(Bugger.scala:16)
[java] at bug.BugRunner$.main(Bugger.scala:19)
[java] at bug.BugRunner.main(Bugger.scala)
[java] Java Result: 1
$ find bug build.xml -type f -print -exec cat '{}' ';'
bug/Bug.java
package bug;
public interface Bug {
public void whatever( String s1, String ... vWhatever );
}
bug/Bugger.scala
package bug
import java.util.logging.{Level,Logger}
class Bugger extends Bug {
private val olog = Logger.getLogger( classOf[Bugger].getName )
override def whatever( s1:String, vWhatever:String* ) = {
olog.log( Level.INFO, "Got args " + s1 + ", and " + vWhatever.length )
}
}
object BugRunner {
def doWhatever( bug:Bug ) = { bug.whatever( "Boo!" ) }
def main(vArg:Array[String]) = {
doWhatever( new Bugger() )
}
}
build.xml
<?xml version="1.0" encoding="UTF-8" ?>
<project
name="bug"
basedir="."
default="compile"
xmlns="antlib:org.apache.tools.ant"
>
<property name="logging.properties" value="${user.home}/logging.properties" />
<property name="scala.home" value="/usr/local/scala" />
<property name="scala-compiler.jar" value="${scala.home}/lib/scala-compiler.jar"/>
<property name="scala-library.jar" value="${scala.home}/lib/scala-library.jar"/>
<property name="build.dir" location="build" />
<property name="dist.dir" location="dist" />
<property name="project.jar" location="${dist.dir}/bug.jar" />
<path id="project.classpath">
<pathelement location="${scala-compiler.jar}"/>
<pathelement location="${scala-library.jar}"/>
<!--
<pathelement location="${share.home}/jar/scala-swing-2.7.3.jar"/>
-->
</path>
<path id="runjar.classpath">
<path refid="project.classpath" />
<pathelement location="${project.jar}"/>
</path>
<target name="prepare">
<mkdir dir="${build.dir}" />
<mkdir dir="${dist.dir}" />
</target>
<target name="clean"
description="Clean the build area"
>
<delete dir="${build.dir}"/>
</target>
<!-- 4. Define scala compiler command. -->
<target name="init">
<property
name="scala-library.jar"
value="${scala.home}/lib/scala-library.jar"
/>
<path id="build.classpath">
<!--
<pathelement location="${scala-library.jar}"/>
<pathelement location="${your.path}"/>
-->
<pathelement location="${build.dir}"/>
</path>
<taskdef resource="scala/tools/ant/antlib.xml">
<classpath>
<pathelement location="${scala-compiler.jar}"/>
<pathelement location="${scala-library.jar}"/>
</classpath>
</taskdef>
</target>
<target name="project.classes" depends="prepare,init">
<scalac
srcdir="."
destdir="${build.dir}"
force="changed"
unchecked="yes"
classpathref="project.classpath"
>
<include name="**/*.scala"/>
<include name="**/*.java"/>
</scalac>
<javac
srcdir="."
destdir="${build.dir}"
debug="true"
>
<classpath refid="project.classpath" />
<include name="**/*.java" />
</javac>
</target>
<target name="compile" depends="project.classes"
description="Compile the thing"
>
</target>
<target name="jarup" depends="compile"
description="jar up classes"
>
<jar id="jarup"
jarfile="${project.jar}"
basedir="${build.dir}"
index="true"
level="9"
>
<manifest>
<attribute name="Main-Class" value="bug.BugRunner"/>
</manifest>
</jar>
</target>
<target name="runBug"
description="Run the bug demo"
depends="jarup"
>
<java classname="bug.BugRunner"
fork="true">
<classpath refid="runjar.classpath" />
<jvmarg value="-Djava.util.logging.config.file=${logging.properties}" />
</java>
</target>
</project>
@dubochet said:
doStuff
in AbstractBase
has type (Array[Object])Unit
doStuff
in AbstractBase
has type (Sequence[_])Unit
doStuff
is called in Caller
as (Array[Object])Unit
, which has not been overriden.
Should there be a Java bridge method for every star-parameter method that is inherited from Java?
Matt Hellige (hellige) said: The call doesn't need to be from Java... This happens whenever the target of the call is statically typed as the interface:
Java:
public interface Test {
public void foo(String... args);
}
Scala:
class Foo extends Test {
def foo(args: String*) = println(args)
}
new Foo().foo("hi") // fine
(new Foo(): Test).foo("hi") // AbstractMethodError
This is particularly dangerous, of course, because you have no idea where the error will actually occur...
Pavol Vaskovic (pali-at-pali.sk) said: Testcase demonsrating the imprications for overriding var arg methods.
Pavol Vaskovic (pali-at-pali.sk) said: I'm seeing this problem with scala 2.7.5.
This is also impacting the ability to override java methods that use varargs. The overriden methods are never invoked, even though the code compiles without errors.
Running the testcase attached above produces:
JavaPrinter: one two three
JavaPrinter: one two three
Exception in thread "main" java.lang.AbstractMethodError
at Main.doYourThing(Main.java:12)
at Main.main(Main.java:8)
Expected result:
JavaPrinter: one two three
InheritingPrinter extends JavaPrinter: one two three
ScalaPrinter: one two three
Pavol Vaskovic (pali-at-pali.sk) said: Replying to [comment:11 pali@…]:
I'm seeing this problem with scala 2.7.5. I meant 2.7.6.
Coda Hale (codahale) said: Just got bit by this using Scala 2.7.7, and it means I'll be unable to use Scala for this particular project.
@odersky said: This is in part a duplicate of #1342. After the fix of #1342 this still gave a compile tyime error, which is now fixed (for 2.8) in r19656.
Pavol Vaskovic (pali-at-pali.sk) said: Martin, any thoughts on backporting this fix for 2.7.x ?
Pavol Vaskovic (pali-at-pali.sk) said: Verified. [attachment:ticket:1459:VarArgOverride_TestCase.zip Testcase] works fine in r19664.
joe (barillari) said: in the "integer" folder, run "run.sh" to trigger the AbstractMethodError.
joe (barillari) said: I believe this bug is not completely fixed in 2.8.1.
I just tried hkulmala's example and it ran without a hitch. But when I changed AbstractBase to a generic type and instantiated it with a java.lang.Integer, the runtime threw an AbstractMethodError.
Here is AbstractBase.java:
public abstract class AbstractBase<T> {
abstract void doStuff(T... params);
void callDoStuff(T... params) {
doStuff(params);
}
Concrete.scala:
class Concrete extends AbstractBase[java.lang.Integer] {
override def doStuff(params:java.lang.Integer*) = println("doStuff invoked")
}
Invoker.scala:
object Invoker {
def main(args: Array[String]) {
val impl = new Concrete
impl.callDoStuff(1,2,3)
}
}
If I compile and run with:
javac *.java && scalac *.scala && scala Invoker
The result is:
java.lang.AbstractMethodError: AbstractBase.doStuff([Ljava/lang/Object;)V
at AbstractBase.callDoStuff(AbstractBase.java:5)
at Invoker$$.main(Invoker.scala:4)
at Invoker.main(Invoker.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at scala.tools.nsc.util.ScalaClassLoader$$$$anonfun$$run$$1.apply(ScalaClassLoader.scala:81)
at scala.tools.nsc.util.ScalaClassLoader$$class.asContext(ScalaClassLoader.scala:24)
at scala.tools.nsc.util.ScalaClassLoader$$URLClassLoader.asContext(ScalaClassLoader.scala:86)
at scala.tools.nsc.util.ScalaClassLoader$$class.run(ScalaClassLoader.scala:81)
at scala.tools.nsc.util.ScalaClassLoader$$URLClassLoader.run(ScalaClassLoader.scala:86)
at scala.tools.nsc.MainGenericRunner$$.main(MainGenericRunner.scala:83)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
Interestingly, if you replace java.lang.Integer with java.lang.Object and alter the call to callDoStuff accordingly, the code works without a hitch.
For the record, I'm running:
$$ scala -version
javaScala code runner version 2.8.1.final -- Copyright 2002-2010, LAMP/EPFL
$$ java -version
java version "1.6.0_18"
OpenJDK Runtime Environment (IcedTea6 1.8.2) (6b18-1.8.2-4ubuntu2)
OpenJDK Server VM (build 16.0-b13, mixed mode)
I have attached a .zip file containing a directory called "object", which instantiates AbstractBase with a java.lang.Object and works, and another directory called "integer", which instantiates AbstractBase with a java.lang.Integer and does not work.
Charles Beyer (cjbeyer) said: I believe I'm hitting this bug in 2.8.0 and 2.8.1 final.
The bug isn't triggered if I change the java abstract method definition from package private (no qualifier) to public.
Also, in my program, the java method doesn't have to be abstract. If I have a dumb generic implementation, the java implementation will get called when I call the method from java, while the scala overriding implementation gets called from scala.
So the bug seems to be related to problems with the visibility qualifiers.
@paulp said (edited on Dec 29, 2011 7:05:35 AM UTC): This bug is still in trunk. The reason is this "except" business in UnCurry:
* - for every repeated Scala parameter `x: T*' --> x: Seq[T].
* - for every repeated Java parameter `x: T...' --> x: Array[T], except:
* if T is an unbounded abstract type, replace --> x: Array[Object]
Referring to joe's comment above mine, this:
public abstract class AbstractBase<T> {
abstract void doStuff(T... params);
}
What happens is that after uncurry that method looks like doStuff(Array[Object]), and so the overriding pair checks during erasure which would insert the necessary bridge do not recognize that the methods have the same signature, because the override's parameter is Array[Integer], not Array[Object].
I put a shameful hack here which makes the problem go away in this instance:
https://github.com/paulp/scala/tree/ticket/SI-1459
But I can't commit that so it's only there for reference.
@paulp said: Interesting, I didn't realize it at the time but it sounds from my description above that this is intimately related to #3452.
François-Xavier Thomas (frx) said: Just ran into it, so any progress on that issue?
Philippe Sam-Long (pulsation) said: Looks like I also ran into this issue extending AsyncTask on android:
E/AndroidRuntime( 1320): FATAL EXCEPTION: AsyncTask #1
E/AndroidRuntime( 1320): java.lang.RuntimeException: An error occured while executing doInBackground()
E/AndroidRuntime( 1320): at android.os.AsyncTask$3.done(AsyncTask.java:299)
E/AndroidRuntime( 1320): at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
E/AndroidRuntime( 1320): at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
E/AndroidRuntime( 1320): at java.util.concurrent.FutureTask.run(FutureTask.java:239)
E/AndroidRuntime( 1320): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
E/AndroidRuntime( 1320): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
E/AndroidRuntime( 1320): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
E/AndroidRuntime( 1320): at java.lang.Thread.run(Thread.java:841)
E/AndroidRuntime( 1320): Caused by: java.lang.AbstractMethodError: abstract method not implemented
E/AndroidRuntime( 1320): at android.os.AsyncTask.doInBackground(AsyncTask.java)
E/AndroidRuntime( 1320): at android.os.AsyncTask$2.call(AsyncTask.java:287)
E/AndroidRuntime( 1320): at java.util.concurrent.FutureTask.run(FutureTask.java:234)
E/AndroidRuntime( 1320): ... 4 more
Here is a workaround for this specific case: https://www.assembla.com/code/scala-eclipse-toolchain/git/nodes/ad17dd4047ac25b167496db84f4272795eb93c3e/docs/android-examples/android-sdk/Wiktionary/src/com/example/android/wiktionary/MyAsyncTask.java
Kirill Lastovirya (kirhgoff) said: Tried to adopt this library https://github.com/Gottox/socket.io-java-client in scala code and faced same issue. Cannot implement interface IOCallback as it has this method in java
void on(java.lang.String s, io.socket.IOAcknowledge ioAcknowledge, java.lang.Object... objects);
and scala compiler gives the following error:
IoClient.scala:20: object creation impossible, since method on in trait IOCallback of type (x$1: String, x$2: io.socket.IOAcknowledge, x$3:
Tried a lot of variants, most reasonable (but still failing) one is def on(event: String, ack: IOAcknowledge, params: Object*)
@jrudolph said: As I'm currently in the awkward position of dealing with Java Interop and also got hurt by this issue I compiled a cabinet of all the different cases I could think of that show problems wrt @varargs methods that still exist in Scala 2.11.4.
See https://github.com/jrudolph/scala-broken-java-varargs/blob/master/src/test/java/example/Test.java
@skyluc said: The original problem has been fixed sometime before 2.10.1, but I could the 'AbstractMethodError' problem from Johannes test code.
Arjun Panday (joune) said: May I submit a similar use case, summarized in this very simple gist: https://gist.github.com/joune/494f7bba4c6889572bb4
=> Exception in thread "main" java.lang.AbstractMethodError: Impl.h(Ljava/lang/Object;[Ljava/lang/String;)Ljava/lang/String;
It seems to work if I remove either the type parameter or the varargs.
Java(TM) SE Runtime Environment (build 1.8.0_25-b17) Scala code runner version 2.11.6 -- Copyright 2002-2013, LAMP/EPFL
@adriaanm said: https://github.com/scala/scala/pull/5631
To see this error in action, just unzip the attachment and run compile.bat followed with run.bat.
I have a base class (Java) with one method:
I create an implementation for it in scala:
Finally, I have a Caller class (Java) which just calls the abovementioned method, as follows:
Now, a direct call succeeds:
whereas the following fails
javac -version gives "1.6.0" scalac -version gives "Scala compiler version 2.7.2.RC4"
I am running on Windows XP SP2 with scala 2.7.2.RC4.