Skip to content

Commit 30c95c8

Browse files
bishaboshaWojciechMazur
authored andcommitted
Widen prefix in findRef of class from Java sources.
potential TODO: tree's of Raw types from Java are still incorrect once they are serialized to TASTy, however it is debateable if we care to support them. [Cherry-picked 3ab2999]
1 parent e0803a0 commit 30c95c8

File tree

14 files changed

+433
-4
lines changed

14 files changed

+433
-4
lines changed

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,6 +1501,13 @@ object SymDenotations {
15011501
def namedType(using Context): NamedType =
15021502
if (isType) typeRef else termRef
15031503

1504+
/** Like typeRef, but the prefix is widened.
1505+
*
1506+
* See tests/neg/i19619/Test.scala
1507+
*/
1508+
def javaTypeRef(using Context) =
1509+
TypeRef(maybeOwner.reachablePrefix.widen, symbol)
1510+
15041511
/** Like typeRef, but objects in the prefix are represented by their singleton type,
15051512
* this means we output `pre.O.member` rather than `pre.O$.this.member`.
15061513
*

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
453453
if (isSelfDenot(defDenot)) curOwner.enclosingClass.thisType
454454
else if (ctx.isJava && defDenot.symbol.isStatic) {
455455
defDenot.symbol.namedType
456+
}
457+
else if (ctx.isJava && defDenot.symbol.isClass) {
458+
// in a java context a raw identifier to a class should have a widened prefix.
459+
defDenot.symbol.javaTypeRef
456460
} else {
457461
val effectiveOwner =
458462
if (curOwner.isTerm && defDenot.symbol.maybeOwner.isType)
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package a;
2+
3+
public class InnerClass {
4+
5+
public class Inner<U> {
6+
public U innerField;
7+
8+
public Inner(U innerField) {
9+
this.innerField = innerField;
10+
}
11+
12+
public U getInnerField() {
13+
return innerField;
14+
}
15+
}
16+
17+
public class Outer<U> {
18+
19+
public class Nested<V> {
20+
21+
public U outerField;
22+
public V innerField;
23+
24+
public Nested(U outerField, V innerField) {
25+
this.outerField = outerField;
26+
this.innerField = innerField;
27+
}
28+
29+
public U getOuterField() {
30+
return outerField;
31+
}
32+
33+
public V getInnerField() {
34+
return innerField;
35+
}
36+
}
37+
}
38+
39+
public <U> Inner<U> createInner(U innerField) {
40+
return new Inner<>(innerField);
41+
}
42+
43+
public <U, V> Outer<U>.Nested<V> createNested(U outerField, V innerField) {
44+
Outer<U> outer = new Outer<>();
45+
return outer.new Nested<>(outerField, innerField);
46+
}
47+
48+
public static <U> InnerClass.Inner<U> createInnerStatic(U innerField) {
49+
InnerClass innerClass = new InnerClass();
50+
return innerClass.new Inner<>(innerField);
51+
}
52+
53+
public static <U, V> InnerClass.Outer<U>.Nested<V> createNestedStatic(U outerField, V innerField) {
54+
InnerClass innerClass = new InnerClass();
55+
InnerClass.Outer<U> outer = innerClass.new Outer<>();
56+
return outer.new Nested<>(outerField, innerField);
57+
}
58+
59+
public static <U, V> void consumeNestedStatic(InnerClass.Outer<U>.Nested<V> nested) {
60+
}
61+
62+
public static <U, V> void consumeNestedStatic2(Outer<U>.Nested<V> nested) {
63+
}
64+
65+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package a;
2+
3+
public class InnerClassGen<T> {
4+
5+
public class Inner<U> {
6+
public T rootField;
7+
public U innerField;
8+
9+
public Inner(T rootField, U innerField) {
10+
this.rootField = rootField;
11+
this.innerField = innerField;
12+
}
13+
14+
public T getRootField() {
15+
return rootField;
16+
}
17+
18+
public U getInnerField() {
19+
return innerField;
20+
}
21+
}
22+
23+
public class Outer<U> {
24+
25+
public class Nested<V> {
26+
public T rootField;
27+
public U outerField;
28+
public V innerField;
29+
30+
public Nested(T rootField, U outerField, V innerField) {
31+
this.rootField = rootField;
32+
this.outerField = outerField;
33+
this.innerField = innerField;
34+
}
35+
36+
public T getRootField() {
37+
return rootField;
38+
}
39+
40+
public U getOuterField() {
41+
return outerField;
42+
}
43+
44+
public V getInnerField() {
45+
return innerField;
46+
}
47+
}
48+
}
49+
50+
public static class OuterStatic<U> {
51+
public static class NestedStatic<V> {
52+
}
53+
}
54+
55+
public <U> Inner<U> createInner(T rootField, U innerField) {
56+
return new Inner<>(rootField, innerField);
57+
}
58+
59+
public <U, V> Outer<U>.Nested<V> createNested(T rootField, U outerField, V innerField) {
60+
Outer<U> outer = new Outer<>();
61+
return outer.new Nested<>(rootField, outerField, innerField);
62+
}
63+
64+
public static <T, U> InnerClassGen<T>.Inner<U> createInnerStatic(T rootField, U innerField) {
65+
InnerClassGen<T> innerClassGen = new InnerClassGen<>();
66+
return innerClassGen.new Inner<>(rootField, innerField);
67+
}
68+
69+
public static <T, U, V> InnerClassGen<T>.Outer<U>.Nested<V> createNestedStatic(T rootField, U outerField, V innerField) {
70+
InnerClassGen<T> innerClassGen = new InnerClassGen<>();
71+
InnerClassGen<T>.Outer<U> outer = innerClassGen.new Outer<>();
72+
return outer.new Nested<>(rootField, outerField, innerField);
73+
}
74+
75+
public static <T, U, V> void consumeNestedStatic(InnerClassGen<T>.Outer<U>.Nested<V> nested) {
76+
}
77+
78+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package a;
2+
3+
public class RawTypes {
4+
5+
public class C<T> {
6+
public class D<U> {
7+
}
8+
}
9+
10+
public static void mii_Raw_Raw(RawTypes.C.D d) {
11+
}
12+
13+
public static void mii_Raw_Raw2(C.D d) {
14+
}
15+
16+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// THIS FILE EXISTS SO THAT `A.java` WILL BE COMPILED BY SCALAC
2+
package a
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package b
2+
3+
import a.InnerClass
4+
import a.InnerClassGen
5+
import a.RawTypes
6+
7+
object B {
8+
@main def test = {
9+
locally {
10+
val ici: InnerClass = new InnerClass()
11+
// val ici_inner1: ici.Inner[Long] = ici.createInner[Long](47L) // error
12+
val ici_inner2: InnerClass#Inner[Long] = ici.createInner[Long](47L)
13+
val ici_inner3: InnerClass#Inner[Long] = InnerClass.createInnerStatic[Long](47L)
14+
15+
val ici_outer: InnerClass#Outer[Long] = new ici.Outer[Long]()
16+
val ici_nested1: InnerClass#Outer[Long]#Nested[Int] = new ici_outer.Nested[Int](47L, 23)
17+
val ici_nested2: InnerClass#Outer[Long]#Nested[Int] = ici.createNested[Long, Int](47L, 23)
18+
val ici_nested3: InnerClass#Outer[Long]#Nested[Int] = InnerClass.createNestedStatic[Long, Int](47L, 23)
19+
20+
InnerClass.consumeNestedStatic(ici_nested3)
21+
InnerClass.consumeNestedStatic2(ici_nested3)
22+
}
23+
24+
locally {
25+
val ici: InnerClassGen[String] = new InnerClassGen()
26+
// val ici_inner1: ici.Inner[Long] = ici.createInner[Long]("Hello", 47L) // error
27+
val ici_inner2: InnerClassGen[String]#Inner[Long] = ici.createInner[Long]("Hello", 47L)
28+
val ici_inner3: InnerClassGen[String]#Inner[Long] = InnerClassGen.createInnerStatic[String, Long]("Hello", 47L)
29+
30+
val ici_outer: InnerClassGen[String]#Outer[Long] = new ici.Outer[Long]()
31+
val ici_nested1: InnerClassGen[String]#Outer[Long]#Nested[Int] = new ici_outer.Nested[Int]("Hello", 47L, 23)
32+
val ici_nested2: InnerClassGen[String]#Outer[Long]#Nested[Int] = ici.createNested[Long, Int]("Hello", 47L, 23)
33+
val ici_nested3: InnerClassGen[String]#Outer[Long]#Nested[Int] = InnerClassGen.createNestedStatic[String, Long, Int]("Hello", 47L, 23)
34+
35+
InnerClassGen.consumeNestedStatic(ici_nested3)
36+
}
37+
38+
locally {
39+
val rt: RawTypes = new RawTypes()
40+
val c: RawTypes#C[String] = new rt.C[String]()
41+
42+
val cd_ii: RawTypes#C[String]#D[String] = new c.D[String]()
43+
val cd_ii_Raw: RawTypes#C[?]#D[?] = cd_ii
44+
45+
RawTypes.mii_Raw_Raw(cd_ii_Raw)
46+
// RawTypes.mii_Raw_Raw2(cd_ii_Raw) // error: dotty still doesnt rewrite the tree of a raw type to a type with wildcards
47+
}
48+
}
49+
50+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
lazy val a = project.in(file("a"))
2+
.settings(
3+
scalacOptions += "-Yjava-tasty", // enable pickling of java signatures
4+
scalacOptions ++= Seq("-Yjava-tasty-output", ((ThisBuild / baseDirectory).value / "a-paths-java-tasty.jar").toString),
5+
scalacOptions += "-Ycheck:all",
6+
Compile / classDirectory := ((ThisBuild / baseDirectory).value / "a-paths-classes"), // send classfiles to a different directory
7+
)
8+
9+
lazy val b = project.in(file("b"))
10+
.settings(
11+
Compile / unmanagedClasspath := Seq(Attributed.blank((ThisBuild / baseDirectory).value / "a-paths-java-tasty.jar")),
12+
scalacOptions += "-Ycheck:all",
13+
scalacOptions += "-explain-cyclic",
14+
scalacOptions += "-Ydebug-cyclic",
15+
)
16+
.settings(
17+
fork := true, // we have to fork the JVM if we actually want to run the code with correct failure semantics
18+
Runtime / unmanagedClasspath += Attributed.blank((ThisBuild / baseDirectory).value / "a-paths-classes"), // make sure the java classes are visible at runtime
19+
)
20+
21+
// same as b, but adds the real classes to the classpath instead of the tasty jar
22+
lazy val bAlt = project.in(file("b-alt"))
23+
.settings(
24+
Compile / sources := (b / Compile / sources).value,
25+
Compile / unmanagedClasspath := Seq(Attributed.blank((ThisBuild / baseDirectory).value / "a-paths-classes")),
26+
scalacOptions += "-Ycheck:all",
27+
)
28+
.settings(
29+
fork := true, // we have to fork the JVM if we actually want to run the code with correct failure semantics
30+
Runtime / unmanagedClasspath += Attributed.blank((ThisBuild / baseDirectory).value / "a-paths-classes"), // make sure the java classes are visible at runtime
31+
)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import sbt._
2+
import Keys._
3+
4+
object DottyInjectedPlugin extends AutoPlugin {
5+
override def requires = plugins.JvmPlugin
6+
override def trigger = allRequirements
7+
8+
override val projectSettings = Seq(
9+
scalaVersion := sys.props("plugin.scalaVersion"),
10+
scalacOptions += "-source:3.0-migration"
11+
)
12+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
> a/compile
2+
# test depending on variations of Java paths
3+
> b/run
4+
# double check against the real java classes
5+
> bAlt/run

tests/neg/i19619/InnerClass.java

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// InnerClass.java
2+
3+
package lib;
4+
5+
public class InnerClass {
6+
7+
public class Inner<U> {
8+
public U innerField;
9+
10+
public Inner(U innerField) {
11+
this.innerField = innerField;
12+
}
13+
14+
public U getInnerField() {
15+
return innerField;
16+
}
17+
}
18+
19+
public class Outer<U> {
20+
21+
public class Nested<V> {
22+
23+
public U outerField;
24+
public V innerField;
25+
26+
public Nested(U outerField, V innerField) {
27+
this.outerField = outerField;
28+
this.innerField = innerField;
29+
}
30+
31+
public U getOuterField() {
32+
return outerField;
33+
}
34+
35+
public V getInnerField() {
36+
return innerField;
37+
}
38+
}
39+
}
40+
41+
public <U> Inner<U> createInner(U innerField) {
42+
return new Inner<>(innerField);
43+
}
44+
45+
public <U, V> Outer<U>.Nested<V> createNested(U outerField, V innerField) {
46+
Outer<U> outer = new Outer<>();
47+
return outer.new Nested<>(outerField, innerField);
48+
}
49+
50+
public static <U> InnerClass.Inner<U> createInnerStatic(U innerField) {
51+
InnerClass innerClass = new InnerClass();
52+
return innerClass.new Inner<>(innerField);
53+
}
54+
55+
public static <U, V> InnerClass.Outer<U>.Nested<V> createNestedStatic(U outerField, V innerField) {
56+
InnerClass innerClass = new InnerClass();
57+
InnerClass.Outer<U> outer = innerClass.new Outer<>();
58+
return outer.new Nested<>(outerField, innerField);
59+
}
60+
61+
public static <U, V> void consumeNestedStatic(InnerClass.Outer<U>.Nested<V> nested) {
62+
}
63+
64+
public static <U, V> void consumeNestedStatic2(Outer<U>.Nested<V> nested) {
65+
}
66+
67+
}

0 commit comments

Comments
 (0)