Skip to content

Commit

Permalink
In Java sources, allow a non-stable prefix for a class parent.
Browse files Browse the repository at this point in the history
(If we widen Foo.this.Inner in the parents of a class to AbstractFoo#Inner, i.e.
  an inherited class Inner prefixed by its owner abstract class AbstractFoo,
  this is not considered a stable prefix for a class parent type.
  But in Java this is the correct type so allow it.)
  • Loading branch information
bishabosha committed Feb 22, 2024
1 parent e8e295a commit d37857c
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 4 deletions.
12 changes: 8 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1542,17 +1542,19 @@ class Namer { typer: Typer =>
end parentType

/** Check parent type tree `parent` for the following well-formedness conditions:
* (1) It must be a class type with a stable prefix (@see checkClassTypeWithStablePrefix)
* (1) It must be a class type with a stable prefix (unless `isJava`) (@see checkClassTypeWithStablePrefix)
* (2) If may not derive from itself
* (3) The class is not final
* (4) If the class is sealed, it is defined in the same compilation unit as the current class
*
* @param isJava If true, the parent type is in Java mode, and we do not require a stable prefix
*/
def checkedParentType(parent: untpd.Tree): Type = {
def checkedParentType(parent: untpd.Tree, isJava: Boolean): Type = {
val ptype = parentType(parent)(using completerCtx.superCallContext).dealiasKeepAnnots
if (cls.isRefinementClass) ptype
else {
val pt = checkClassType(ptype, parent.srcPos,
traitReq = parent ne parents.head, stablePrefixReq = true)
traitReq = parent ne parents.head, stablePrefixReq = !isJava)
if (pt.derivesFrom(cls)) {
val addendum = parent match {
case Select(qual: Super, _) if Feature.migrateTo3 =>
Expand Down Expand Up @@ -1621,7 +1623,9 @@ class Namer { typer: Typer =>
val parentTypes = defn.adjustForTuple(cls, cls.typeParams,
defn.adjustForBoxedUnit(cls,
addUsingTraits(
ensureFirstIsClass(cls, parents.map(checkedParentType(_)))
locally:
val isJava = ctx.isJava
ensureFirstIsClass(cls, parents.map(checkedParentType(_, isJava)))
)
)
)
Expand Down
52 changes: 52 additions & 0 deletions sbt-test/pipelining/Yjava-tasty-paths/a/InnerClassSub.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package a;

public class InnerClassSub extends InnerClass {

public class InnerSub<U> extends Inner<U> {
public InnerSub(U innerField) {
super(innerField);
}
}

public class OuterSub<U> extends Outer<U> {
public OuterSub() {
super();
}
}

public <U> Inner<U> createInnerSub(U innerField) {
return new InnerSub<>(innerField);
}

public <U, V> Outer<U>.Nested<V> createNestedSub(U outerField, V innerField) {
OuterSub<U> outer = new OuterSub<>();
return outer.new Nested<>(outerField, innerField);
}

public <U> InnerClass.Inner<U> createInnerSub2(U innerField) {
return new InnerSub<>(innerField);
}

public <U, V> InnerClass.Outer<U>.Nested<V> createNestedSub2(U outerField, V innerField) {
OuterSub<U> outer = new OuterSub<>();
return outer.new Nested<>(outerField, innerField);
}

public static <U> InnerClass.Inner<U> createInnerStatic(U innerField) {
InnerClassSub innerClass = new InnerClassSub();
return innerClass.new Inner<>(innerField);
}

public static <U, V> InnerClass.Outer<U>.Nested<V> createNestedStatic(U outerField, V innerField) {
InnerClassSub innerClass = new InnerClassSub();
InnerClassSub.Outer<U> outer = innerClass.new Outer<>();
return outer.new Nested<>(outerField, innerField);
}

public static <U, V> void consumeNestedStatic(InnerClass.Outer<U>.Nested<V> nested) {
}

public static <U, V> void consumeNestedStatic2(Outer<U>.Nested<V> nested) {
}

}
18 changes: 18 additions & 0 deletions sbt-test/pipelining/Yjava-tasty-paths/b/Test.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package b
import a.InnerClass
import a.InnerClassGen
import a.RawTypes
import a.InnerClassSub

object B {
@main def test = {
Expand Down Expand Up @@ -45,6 +46,23 @@ object B {
RawTypes.mii_Raw_Raw(cd_ii_Raw)
RawTypes.mii_Raw_Raw2(cd_ii_Raw)
}

locally {
val ici: InnerClassSub = new InnerClassSub()
// val ici_inner1: ici.Inner[Long] = ici.createInner[Long](47L) // error
val ici_inner2: InnerClass#Inner[Long] = ici.createInnerSub[Long](47L)
val ici_inner2_2: InnerClass#Inner[Long] = ici.createInnerSub2[Long](47L)
val ici_inner3: InnerClass#Inner[Long] = InnerClassSub.createInnerStatic[Long](47L)

val ici_outer: InnerClassSub#Outer[Long] = new ici.Outer[Long]()
val ici_nested1: InnerClassSub#Outer[Long]#Nested[Int] = new ici_outer.Nested[Int](47L, 23)
val ici_nested2: InnerClass#Outer[Long]#Nested[Int] = ici.createNestedSub[Long, Int](47L, 23)
val ici_nested2_2: InnerClass#Outer[Long]#Nested[Int] = ici.createNestedSub2[Long, Int](47L, 23)
val ici_nested3: InnerClass#Outer[Long]#Nested[Int] = InnerClassSub.createNestedStatic[Long, Int](47L, 23)

InnerClass.consumeNestedStatic(ici_nested3)
InnerClass.consumeNestedStatic2(ici_nested3)
}
}

}
54 changes: 54 additions & 0 deletions tests/run/i19619/InnerClassSub.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// InnerClass.java

package lib;

public class InnerClassSub extends InnerClass {

public class InnerSub<U> extends Inner<U> {
public InnerSub(U innerField) {
super(innerField);
}
}

public class OuterSub<U> extends Outer<U> {
public OuterSub() {
super();
}
}

public <U> Inner<U> createInnerSub(U innerField) {
return new InnerSub<>(innerField);
}

public <U, V> Outer<U>.Nested<V> createNestedSub(U outerField, V innerField) {
OuterSub<U> outer = new OuterSub<>();
return outer.new Nested<>(outerField, innerField);
}

public <U> InnerClass.Inner<U> createInnerSub2(U innerField) {
return new InnerSub<>(innerField);
}

public <U, V> InnerClass.Outer<U>.Nested<V> createNestedSub2(U outerField, V innerField) {
OuterSub<U> outer = new OuterSub<>();
return outer.new Nested<>(outerField, innerField);
}

public static <U> InnerClass.Inner<U> createInnerStatic(U innerField) {
InnerClassSub innerClass = new InnerClassSub();
return innerClass.new Inner<>(innerField);
}

public static <U, V> InnerClass.Outer<U>.Nested<V> createNestedStatic(U outerField, V innerField) {
InnerClassSub innerClass = new InnerClassSub();
InnerClassSub.Outer<U> outer = innerClass.new Outer<>();
return outer.new Nested<>(outerField, innerField);
}

public static <U, V> void consumeNestedStatic(InnerClass.Outer<U>.Nested<V> nested) {
}

public static <U, V> void consumeNestedStatic2(Outer<U>.Nested<V> nested) {
}

}
17 changes: 17 additions & 0 deletions tests/run/i19619/Test.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import lib.InnerClass
import lib.InnerClassGen
import lib.RawTypes
import lib.InnerClassSub

@main def Test =

Expand Down Expand Up @@ -40,3 +41,19 @@ import lib.RawTypes

RawTypes.mii_Raw_Raw(cd_ii_Raw)
RawTypes.mii_Raw_Raw2(cd_ii_Raw)

locally:
val ici: InnerClassSub = new InnerClassSub()
// val ici_inner1: ici.Inner[Long] = ici.createInner[Long](47L) // error
val ici_inner2: InnerClass#Inner[Long] = ici.createInnerSub[Long](47L)
val ici_inner2_2: InnerClass#Inner[Long] = ici.createInnerSub2[Long](47L)
val ici_inner3: InnerClass#Inner[Long] = InnerClassSub.createInnerStatic[Long](47L)

val ici_outer: InnerClassSub#Outer[Long] = new ici.Outer[Long]()
val ici_nested1: InnerClassSub#Outer[Long]#Nested[Int] = new ici_outer.Nested[Int](47L, 23)
val ici_nested2: InnerClass#Outer[Long]#Nested[Int] = ici.createNestedSub[Long, Int](47L, 23)
val ici_nested2_2: InnerClass#Outer[Long]#Nested[Int] = ici.createNestedSub2[Long, Int](47L, 23)
val ici_nested3: InnerClass#Outer[Long]#Nested[Int] = InnerClassSub.createNestedStatic[Long, Int](47L, 23)

InnerClass.consumeNestedStatic(ici_nested3)
InnerClass.consumeNestedStatic2(ici_nested3)

0 comments on commit d37857c

Please sign in to comment.