Skip to content
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

@vararg annotation when called from Java does not compile #7212

Closed
ekrich opened this issue Sep 12, 2019 · 9 comments · Fixed by #9271
Closed

@vararg annotation when called from Java does not compile #7212

ekrich opened this issue Sep 12, 2019 · 9 comments · Fixed by #9271

Comments

@ekrich
Copy link
Contributor

ekrich commented Sep 12, 2019

minimized code

object foo {
  def main(args: Array[String]): Unit = {
    println("Dotty")
    // calling from Java does not compile
    val config = new SimpleConfig
    config.checkValid(config, "foo")
  }
  
  import scala.annotation.varargs
  
  trait Config {
    @varargs def checkValid(reference: Config, restrictToPaths: String*): Unit
  }

  class SimpleConfig extends Config {
    // This method in Config uses @varargs so it can be called from Java with varargs
    // See https://github.com/scala/bug/issues/10658
    // Now the code goes through the Scala varargs method but we need this one for Java
    def checkValid(reference: Config, restrictToPaths: Array[String]): Unit = {
      println("called from Java checkValid")
      checkValid(reference, restrictToPaths.toIndexedSeq: _*)
    }	

    override def checkValid(reference: Config, restrictToPaths: String*): Unit = {
      println("called from Scala checkValid")
    }
  }
}

expectation

Calling from Scala works as expected compared to Scala 2. In Dotty calling from Java does not compile and it looks like it calls the Scala method based on the error.

[error] /Users/eric/workspace/sconfig/examples/java/simple-lib/src/main/java/simplelib/SimpleLibContext.java:21:1: incompatible types: java.lang.String cannot be converted to scala.collection.immutable.Seq<java.lang.String>
[error]         config.checkValid(ConfigFactory.defaultReference(), "simple-lib");

Reference used when porting https://github.com/ekrich/sconfig from Java to Scala. scala/bug#10658

@som-snytt
Copy link
Contributor

Someone (SO) asked about overloaded

  def set[S](values: Array[S]): Unit = { 
    println("Array overload")
  }

  @annotation.varargs
  def set[S](value: S, values: S*): Unit = {
    println("Varargs overload")
  } 

and invocation from Java

set(true)

In Scala 3, modulo varargs, the signature is

  public <S extends java.lang.Object> void set(S[]);
    descriptor: (Ljava/lang/Object;)V

instead of

  public <S extends java.lang.Object> void set(java.lang.Object);
    descriptor: (Ljava/lang/Object;)V

Now, whenever something doesn't work as expected, we ask, WWDD?

@ohze
Copy link

ohze commented Mar 3, 2020

Are there any workaround for this issue now?
(How can we define a varargs method in dotty that can be called from java?)

Minimal test code:

class Dotty {
  @annotation.varargs def f(a: String*)= ???
}
public class Java {
    Dotty d = null;
    public void test() {
        d.f("a", "b");
    }
}
[error] .../Java.java:4:1: method f in class Dotty cannot be applied to given types;
[error]   required: scala.collection.immutable.Seq<java.lang.String>
[error]   found: java.lang.String,java.lang.String
[error]   reason: actual and formal argument lists differ in length
[error] d.f

@som-snytt
Copy link
Contributor

som-snytt commented Mar 3, 2020

I just did the thing where I forgot to import annotation._. That sure is annoying.

Anyway, the ball is now in javac's court:

➜  dotty git:(review/7212) ✗ javac  t7212.java 
An exception has occurred in the compiler (11.0.5). Please file a bug against the Java compiler via the Java bug reporting page (http://bugreport.java.com) after checking the Bug Database (http://bugs.java.com) for duplicates. Include your program and the following diagnostic in your report. Thank you.
java.lang.NullPointerException
	at jdk.compiler/com.sun.tools.javac.comp.Flow$FlowAnalyzer.visitApply(Flow.java:1235)
	at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1634)
	at jdk.compiler/com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
	at jdk.compiler/com.sun.tools.javac.comp.Flow$BaseAnalyzer.scan(Flow.java:398)
	at jdk.compiler/com.sun.tools.javac.tree.TreeScanner.visitExec(TreeScanner.java:213)
	at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCExpressionStatement.accept(JCTree.java:1452)
	at jdk.compiler/com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
	at jdk.compiler/com.sun.tools.javac.comp.Flow$BaseAnalyzer.scan(Flow.java:398)
	at jdk.compiler/com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:57)
	at jdk.compiler/com.sun.tools.javac.comp.Flow$FlowAnalyzer.visitBlock(Flow.java:997)
	at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:1020)
	at jdk.compiler/com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
	at jdk.compiler/com.sun.tools.javac.comp.Flow$BaseAnalyzer.scan(Flow.java:398)
	at jdk.compiler/com.sun.tools.javac.comp.Flow$FlowAnalyzer.visitMethodDef(Flow.java:964)
	at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:866)
	at jdk.compiler/com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
	at jdk.compiler/com.sun.tools.javac.comp.Flow$BaseAnalyzer.scan(Flow.java:398)
	at jdk.compiler/com.sun.tools.javac.comp.Flow$FlowAnalyzer.visitClassDef(Flow.java:927)
	at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:774)
	at jdk.compiler/com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
	at jdk.compiler/com.sun.tools.javac.comp.Flow$BaseAnalyzer.scan(Flow.java:398)
	at jdk.compiler/com.sun.tools.javac.comp.Flow$FlowAnalyzer.analyzeTree(Flow.java:1327)
	at jdk.compiler/com.sun.tools.javac.comp.Flow$FlowAnalyzer.analyzeTree(Flow.java:1317)
	at jdk.compiler/com.sun.tools.javac.comp.Flow.analyzeTree(Flow.java:218)
	at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1401)
	at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1375)
	at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:973)
	at jdk.compiler/com.sun.tools.javac.main.Main.compile(Main.java:311)
	at jdk.compiler/com.sun.tools.javac.main.Main.compile(Main.java:170)
	at jdk.compiler/com.sun.tools.javac.Main.compile(Main.java:57)
	at jdk.compiler/com.sun.tools.javac.Main.main(Main.java:43)
➜  dotty git:(review/7212) ✗ 

Edit: I see that was already reported on the linked scala ticket.

@ekrich
Copy link
Contributor Author

ekrich commented Mar 3, 2020

Is there a link to the test or anything we can review?

giabao added a commit to ohze/akka that referenced this issue Mar 21, 2020
giabao added a commit to ohze/akka that referenced this issue Mar 31, 2020
giabao added a commit to ohze/akka that referenced this issue Mar 31, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 2, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 5, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 6, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 7, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 7, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 9, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 9, 2020
martijnhoekstra added a commit to martijnhoekstra/util that referenced this issue May 11, 2020
martijnhoekstra added a commit to martijnhoekstra/util that referenced this issue May 11, 2020
giabao added a commit to ohze/scalafix-rules that referenced this issue Jun 6, 2020
@TheElectronWill
Copy link
Member

TheElectronWill commented Jul 1, 2020

It turns out that dotty generates no java varargs method, as if the @varargs annotation was ignored. It seems that @deprecated isn't processed correctly/at all either. I guess the problem lies in the backend?

Side note : javac NPE is gone in openjdk 14

@smarter
Copy link
Member

smarter commented Jul 1, 2020

as if the @VarArgs annotation was ignored

Yeah, it doesn't do anything with it right now.

I guess the problem lies in the backend?

I don't think this needs to be handled in the backend (it isn't in scalac as far as I can see). It should probably be handled in https://github.com/lampepfl/dotty/blob/master/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala which already takes care of adding varargs bridge to scala methods that override java methods.

@TheElectronWill
Copy link
Member

TheElectronWill commented Jul 1, 2020

alright! can I try to implement it there?

What about @deprecated, which should add the deprecated bytecode attribute to the method?

@smarter
Copy link
Member

smarter commented Jul 1, 2020

Sure! For @deprecated there's a TODO in the backend indeed: https://github.com/lampepfl/dotty/blob/baba3f0a610bf971045d69a29d7f9e9c1ce2c8ff/compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala#L325

TheElectronWill added a commit to TheElectronWill/dotty that referenced this issue Jul 1, 2020
@TheElectronWill TheElectronWill linked a pull request Jul 1, 2020 that will close this issue
@ekrich
Copy link
Contributor Author

ekrich commented Jul 13, 2020

Works great!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants