bug icon indicating copy to clipboard operation
bug copied to clipboard

scalac reports error on valid Java class: illegal cyclic reference involving type T

Open scabug opened this issue 14 years ago • 17 comments
trafficstars

When compiling a mix of Java and Scala files, scalac will report an error on otherwise valid Java files.

To reproduce, create 2 files:

Foo.java:

public class Foo<T extends Comparable<? super T>> {}

Bar.scala:

class Bar {
   val quux = new Foo[Int]()
}

And compile them using scalac:

$ scalac Foo.java Bar.scala
Foo.java:1: error: illegal cyclic reference involving type T
public class Foo<T extends Comparable<? super T>> {
                                      ^
one error found

Impact: it's not possible to use scala for mixed Scala/Java projects containing such declarations.

scabug avatar Jun 28 '11 13:06 scabug

Imported From: https://issues.scala-lang.org/browse/SI-4744?orig=1 Reporter: Christoph Breitkopf (bokesan) Affected Versions: 2.9.0, 2.11.2, 2.12.0-M5

scabug avatar Jun 28 '11 13:06 scabug

@paulp said: That's nicely reduced. Given that the scala code compiles fine against the compiled java, there must be something we can do here.

scabug avatar Jun 30 '11 23:06 scabug

@paulp said: https://github.com/scala/scala/pull/1422

scabug avatar Sep 29 '12 04:09 scabug

Bhashit Parikh (bhashit) said (edited on May 31, 2014 3:19:46 PM UTC): I think this is still occurring when the java class in question is being referenced from any scala class.

This is the scenario:

A.java

public class A<T extends Comparable<? super T>> implements Comparable<T> {
  public int compareTo(T other) {
    return 0;
  }
}

B.scala

class B {
  println (new A)
}
  • Command * scalac ./*.java ./\*.scala

If I compile just the java files, it works. If the scala code doesn't refer to that java class, it works.

$ scalac -version
Scala compiler version 2.11.1 -- Copyright 2002-2013, LAMP/EPFL

scabug avatar May 31 '14 15:05 scabug

Dmytro Kondratiuk (dk14) said: Still experiencing issue with 2.11.2, 2.11.5 - http://stackoverflow.com/questions/28158173/building-a-project-with-mixed-scala-and-java-source-files-using-ant-illegal-cy

scabug avatar Jan 27 '15 23:01 scabug

Arif (apathan) said: Under what timeframe will this fix be released? I'd love to start using Scala in our application (that is currently all Java), but can't proceed due to this issue. Any update is greatly appreciated. Thx.

scabug avatar Mar 06 '15 20:03 scabug

Per Mildner (per.mildner-at-sics.se) said: Ping. Any news on this bug?

scabug avatar Jul 01 '15 11:07 scabug

Per Mildner (per.mildner-at-sics.se) said: Any news on this bug? It is unfortunate that Scala can not be mixed with Java classes that implement, e.g. Comparable.

scabug avatar Nov 30 '15 09:11 scabug

Per Mildner (per.mildner-at-sics.se) said: Any news? I this fixed in some other version/branch of Scala?

scabug avatar Aug 09 '16 08:08 scabug

@SethTisue said: 2.12.0-M5 gives the same error

scabug avatar Aug 18 '16 17:08 scabug

@adriaanm @szeiger is someone specific actually intending to tackle this...? if not, let's remove it from the 2.13.0-M4 milestone

SethTisue avatar Feb 06 '18 01:02 SethTisue

"Dotty is so right, it reports it twice!"

➜  t4744 ~/dotty-0.26.0/bin/dotc -d /tmp/ *a
-- [E057] Type Mismatch Error: B.scala:5:23 ------------------------------------
5 |  val quux = new A[Int]()
  |                       ^
  |Type argument Int does not conform to upper bound Comparable[? >: LazyRef(Int)]
-- [E057] Type Mismatch Error: B.scala:5:19 ------------------------------------
5 |  val quux = new A[Int]()
  |                   ^
  |Type argument Int does not conform to upper bound Comparable[? >: LazyRef(Int)]
2 errors found

som-snytt avatar Oct 08 '20 21:10 som-snytt

Hi @SethTisue, any updates on this?

eleansa avatar May 25 '21 16:05 eleansa

@eleansa no. nobody is working on this at present. a pull request with a fix would be very welcome

SethTisue avatar May 25 '21 19:05 SethTisue

Blows up in Typer. There's a "is this defined in Java" predicate in the model, so probably a good application of that where this is checked would suppress the error. The difficulty is figuring out how to not suppress it when it's right...

dwijnand avatar May 26 '21 07:05 dwijnand

Same issue has surfaced in Scala 3.1.2. I did not have this problem with 2.13.

ek-gh avatar Apr 28 '22 00:04 ek-gh

Scala 2 has an experimental option -Ybreak-cycles that avoids the cyclic error.

The program above proceeds to compile as far as:

[error] /Users/jz/code/scala-bug-4744/src/main/scala/Bar.scala:2:7: type arguments [Int] do not conform to class Foo's type parameter bounds [T <: Comparable[_ >: T]
[error]   val quux = new Foo[Int]()
[error]       ^
[error] /Users/jz/code/scala-bug-4744/src/main/scala/Bar.scala:2:18: type arguments [Int] do not conform to class Foo's type parameter bounds [T <: Comparable[_ >: T]]
[error]   val quux = new Foo[Int]()
[error]                  ^

Using val quux = new Foo[String]() instead compiles successfully.

The code that checks for this is:

    def findCyclicalLowerBound(tp: Type): Symbol = {
      tp match {
        case TypeBounds(lo, _) =>
          // check that lower bound is not an F-bound
          // but carefully: class Foo[T <: Bar[_ >: T]] should be allowed
          for (tp1 @ TypeRef(_, sym, _) <- lo) {
            if (settings.breakCycles) {
              if (!sym.maybeInitialize) {
                log(s"Cycle inspecting $lo for possible f-bounds: ${sym.fullLocationString}")
                return sym
              }
            }
            else sym.initialize
          }
        case _ =>
      }
      NoSymbol
    }

The caller to this method knows if we are checking a Java-defined symbol; it could pass this information in we could change the condition to:

if (isJava || settings.breakCycles)`

I'm not 100% sure, but I feel like the better approach might be to use a custom type traverser (rather than tp.foreach) that stops descending at the _ >: T existential.

retronym avatar Jul 08 '22 05:07 retronym