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

"Reference to X is ambiguous" compiling Java code #13106

Closed
ignasi35 opened this issue Jul 19, 2021 · 8 comments · Fixed by #13108
Closed

"Reference to X is ambiguous" compiling Java code #13106

ignasi35 opened this issue Jul 19, 2021 · 8 comments · Fixed by #13108
Assignees
Milestone

Comments

@ignasi35
Copy link
Contributor

ignasi35 commented Jul 19, 2021

The Akka codebase includes some Java code resulting from code generation using protoc from .protobuf files. This Java code is kept under SCM (git) so it is not regenerated over and over.

A particular protobuf file uses protobuf inner messages that result into generating inner classes when producing Java classes for the protobuf messages. Each of the generated classes includes a Builder inner class.

Compiling code that uses those Builder classes produces the following compiler error:

[error] -- [E049] Reference Error: /Users/ignasi/git/github/akka/akka/akka-persistence-scala3/akka-persistence/src/main/java/akka/persistence/serialization/MessageFormats.java:4113:16 
[error] 4113 |      protected Builder newBuilderForType(
[error]      |                ^^^^^^^
[error]      |            Reference to Builder is ambiguous,
[error]      |            it is both defined in object AtLeastOnceDeliverySnapshot
[error]      |            and inherited subsequently in class UnconfirmedDelivery

when compiling this code.
NOTE: this error is a sample, there are a few more identical to that one.

I already tried compiling java sources first as suggested offline by some colleagues (@lrytz) but that workaround is not feasible in this particular codebase, unfortunately, since there are other parts of the build that require compiling Scala first. Using Mixed compile ordering doesn't work around the issue.

Compiler version

3.0.1-RC1

Minimized code

public final class MessageFormats {
    public  static final class AtLeastOnceDeliverySnapshot extends ... {
         public static final class Builder extends ... {
         }
         public  static final class UnconfirmedDelivery extends ... {
             public static final class Builder extends ... {
             }
             // code referring to `Builder` in this block will no longer 
             // compile in scala3
             @java.lang.Override
             protected Builder newBuilderForType(...) {
                  Builder builder = new Builder(parent);
                  return builder;
             }
             ...
         }
    }
}

Or probably smaller:

public final class A {
  public static final class C { }
  public static final class D {
    public static final class C { }
    public C foo() { return new C(); }
  }
}

Expectation

The compile can compile the Java code as it did in 2.13 and previous versions.

@odersky
Copy link
Contributor

odersky commented Jul 19, 2021

I can take a look at this

@lrytz
Copy link
Member

lrytz commented Jul 19, 2021

See scala/scala#5332 and scala/scala#7671 for fixes in this area in scala/scala. At some point in the past, I think the strategy was to represent a Java class

class C {
  static class D
  D foo()
}

using an import

object C:
  class D
class C:
  import C._
  def foo(): D

but we changed this and now there is a java-specific lookup method javaFindMember. It seems dotty is using the "old" strategy.

@smarter
Copy link
Member

smarter commented Jul 19, 2021

It seems dotty is using the "old" strategy.

No we actually ported that change: #12884

@lrytz
Copy link
Member

lrytz commented Jul 19, 2021

Ah, OK. The imports seem to be there after parsing though:

public final class A {
  public static final class C { }
  public static final class D {
    public static final class C { }
    public C foo() { return new C(); }
  }
}
object Test {
  def foo: A.D.C = (new A.D).foo()
}
$> sc3 A.java Test.scala -Xprint:parser
parsed:
package <empty> {
  object A() {
    <static> object C() {}
    final <static> class C private[this](x$1: _root_.scala.Unit) extends _root_.java.lang.Object {
      def <init>()
    }
    <static> object D() {
      <static> object C() {}
      final <static> class C private[this](x$1: _root_.scala.Unit) extends _root_.java.lang.Object {
        def <init>()
      }
    }
    final <static> class D private[this](x$1: _root_.scala.Unit) extends _root_.java.lang.Object {
      import D.*
      def <init>()
      def foo(): C = _root_.scala.Predef.???
    }
  }
  final class A private[this](x$1: _root_.scala.Unit) extends _root_.java.lang.Object {
    import A.*
    def <init>()
  }
}

@smarter
Copy link
Member

smarter commented Jul 19, 2021

I don't see them on master, so I assume you're using an older compiler.

@lrytz
Copy link
Member

lrytz commented Jul 19, 2021

Allright, I tried 3.0.1

@smarter
Copy link
Member

smarter commented Jul 19, 2021

3.0.1 was branched more than six weeks ago so it's old news already ;)

@som-snytt
Copy link
Contributor

sdkman is out of the loop.

➜  ~ sdk list scala
================================================================================
Available Scala Versions
================================================================================
 > * 3.0.0             * 2.12.10             2.11.6
   + 3.0.0-RC1           2.12.9              2.11.5
   + 3.0.0-M3          * 2.12.8              2.11.4
   + 3.0.0-M2          * 2.12.7              2.11.3
   + 3.0.0-M1          * 2.12.6            * 2.11.2

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.

6 participants