diff --git a/compiler/src/dotty/tools/dotc/core/ContextOps.scala b/compiler/src/dotty/tools/dotc/core/ContextOps.scala index 920da377f9b4..55fb31fd1916 100644 --- a/compiler/src/dotty/tools/dotc/core/ContextOps.scala +++ b/compiler/src/dotty/tools/dotc/core/ContextOps.scala @@ -34,7 +34,10 @@ object ContextOps: if (elem.name == name) return elem.sym.denot // return self } val pre = ctx.owner.thisType - if ctx.isJava then javaFindMember(name, pre, required, excluded) + if ctx.isJava then + // Note: I didn't verify if there exists a code path that would require `lookInCompanion = true`, + // it is just to preserve the original behavior. + javaFindMember(name, pre, lookInCompanion = true, required, excluded) else pre.findMember(name, pre, required, excluded) } else // we are in the outermost context belonging to a class; self is invisible here. See inClassContext. @@ -43,7 +46,13 @@ object ContextOps: ctx.scope.denotsNamed(name).filterWithFlags(required, excluded).toDenot(NoPrefix) } - final def javaFindMember(name: Name, pre: Type, required: FlagSet = EmptyFlags, excluded: FlagSet = EmptyFlags): Denotation = + /** Look in the prefix with Java semantics. + * @param lookInCompanion If true, try in the companion class of a module as a fallback. + * Note: originally this was used to type Select nodes in Java code, + * but that is no longer the case. + * It is preserved in case it is necessary for denotNamed, but this is unverified. + */ + final def javaFindMember(name: Name, pre: Type, lookInCompanion: Boolean, required: FlagSet = EmptyFlags, excluded: FlagSet = EmptyFlags): Denotation = assert(ctx.isJava) inContext(ctx) { @@ -53,7 +62,7 @@ object ContextOps: val directSearch = pre.findMember(name, pre, required, excluded) // 2. Try to search in companion class if current is an object. - def searchCompanionClass = if preSym.is(Flags.Module) then + def searchCompanionClass = if lookInCompanion && preSym.is(Flags.Module) then preSym.companionClass.thisType.findMember(name, pre, required, excluded) else NoDenotation diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 13eb5ce8b5ba..b3fe5757720e 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1512,6 +1512,13 @@ object SymDenotations { def namedType(using Context): NamedType = if (isType) typeRef else termRef + /** Like typeRef, but the prefix is widened. + * + * See tests/neg/i19619/Test.scala + */ + def javaTypeRef(using Context) = + TypeRef(maybeOwner.reachablePrefix.widen, symbol) + /** Like typeRef, but objects in the prefix are represented by their singleton type, * this means we output `pre.O.member` rather than `pre.O$.this.member`. * diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 03ff6e168666..7d1134f76d42 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -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 => @@ -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))) ) ) ) diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 8bae3a2fb3a7..96c5e57dde0e 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -156,7 +156,10 @@ trait TypeAssigner { val pre = maybeSkolemizePrefix(qualType, name) val mbr = if ctx.isJava then - ctx.javaFindMember(name, pre) + // don't look in the companion class here if qual is a module, + // we use backtracking to instead change the qual to the companion class + // if this fails. + ctx.javaFindMember(name, pre, lookInCompanion = false) else qualType.findMember(name, pre) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index f1db302e958c..165484091260 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -461,6 +461,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer if (isSelfDenot(defDenot)) curOwner.enclosingClass.thisType else if (ctx.isJava && defDenot.symbol.isStatic) { defDenot.symbol.namedType + } + else if (ctx.isJava && defDenot.symbol.isClass) { + // in a java context a raw identifier to a class should have a widened prefix. + defDenot.symbol.javaTypeRef } else { val effectiveOwner = if (curOwner.isTerm && defDenot.symbol.maybeOwner.isType) @@ -4271,14 +4275,16 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer val tree1 = if ((pt eq AnyTypeConstructorProto) || tp.typeParamSymbols.isEmpty) tree else { - val tp1 = - if (ctx.isJava) - // Cook raw type - AppliedType(tree.tpe, tp.typeParams.map(Function.const(TypeBounds.empty))) - else - // Eta-expand higher-kinded type - tree.tpe.etaExpand(tp.typeParamSymbols) - tree.withType(tp1) + if (ctx.isJava) + // Cook raw type + val typeArgs = tp.typeParams.map(Function.const(TypeBounds.empty)) + val tree1 = AppliedTypeTree(tree, typeArgs.map(TypeTree(_))) + val tp1 = AppliedType(tree.tpe, typeArgs) + tree1.withType(tp1) + else + // Eta-expand higher-kinded type + val tp1 = tree.tpe.etaExpand(tp.typeParamSymbols) + tree.withType(tp1) } if (ctx.mode.is(Mode.Pattern) || ctx.mode.isQuotedPattern || tree1.tpe <:< pt) tree1 else err.typeMismatch(tree1, pt) diff --git a/sbt-test/pipelining/Yjava-tasty-paths/a/InnerClass.java b/sbt-test/pipelining/Yjava-tasty-paths/a/InnerClass.java new file mode 100644 index 000000000000..c23bc54397dd --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-paths/a/InnerClass.java @@ -0,0 +1,65 @@ +package a; + +public class InnerClass { + + public class Inner { + public U innerField; + + public Inner(U innerField) { + this.innerField = innerField; + } + + public U getInnerField() { + return innerField; + } + } + + public class Outer { + + public class Nested { + + public U outerField; + public V innerField; + + public Nested(U outerField, V innerField) { + this.outerField = outerField; + this.innerField = innerField; + } + + public U getOuterField() { + return outerField; + } + + public V getInnerField() { + return innerField; + } + } + } + + public Inner createInner(U innerField) { + return new Inner<>(innerField); + } + + public Outer.Nested createNested(U outerField, V innerField) { + Outer outer = new Outer<>(); + return outer.new Nested<>(outerField, innerField); + } + + public static InnerClass.Inner createInnerStatic(U innerField) { + InnerClass innerClass = new InnerClass(); + return innerClass.new Inner<>(innerField); + } + + public static InnerClass.Outer.Nested createNestedStatic(U outerField, V innerField) { + InnerClass innerClass = new InnerClass(); + InnerClass.Outer outer = innerClass.new Outer<>(); + return outer.new Nested<>(outerField, innerField); + } + + public static void consumeNestedStatic(InnerClass.Outer.Nested nested) { + } + + public static void consumeNestedStatic2(Outer.Nested nested) { + } + +} diff --git a/sbt-test/pipelining/Yjava-tasty-paths/a/InnerClassGen.java b/sbt-test/pipelining/Yjava-tasty-paths/a/InnerClassGen.java new file mode 100644 index 000000000000..4011cf2fc244 --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-paths/a/InnerClassGen.java @@ -0,0 +1,78 @@ +package a; + +public class InnerClassGen { + + public class Inner { + public T rootField; + public U innerField; + + public Inner(T rootField, U innerField) { + this.rootField = rootField; + this.innerField = innerField; + } + + public T getRootField() { + return rootField; + } + + public U getInnerField() { + return innerField; + } + } + + public class Outer { + + public class Nested { + public T rootField; + public U outerField; + public V innerField; + + public Nested(T rootField, U outerField, V innerField) { + this.rootField = rootField; + this.outerField = outerField; + this.innerField = innerField; + } + + public T getRootField() { + return rootField; + } + + public U getOuterField() { + return outerField; + } + + public V getInnerField() { + return innerField; + } + } + } + + public static class OuterStatic { + public static class NestedStatic { + } + } + + public Inner createInner(T rootField, U innerField) { + return new Inner<>(rootField, innerField); + } + + public Outer.Nested createNested(T rootField, U outerField, V innerField) { + Outer outer = new Outer<>(); + return outer.new Nested<>(rootField, outerField, innerField); + } + + public static InnerClassGen.Inner createInnerStatic(T rootField, U innerField) { + InnerClassGen innerClassGen = new InnerClassGen<>(); + return innerClassGen.new Inner<>(rootField, innerField); + } + + public static InnerClassGen.Outer.Nested createNestedStatic(T rootField, U outerField, V innerField) { + InnerClassGen innerClassGen = new InnerClassGen<>(); + InnerClassGen.Outer outer = innerClassGen.new Outer<>(); + return outer.new Nested<>(rootField, outerField, innerField); + } + + public static void consumeNestedStatic(InnerClassGen.Outer.Nested nested) { + } + +} diff --git a/sbt-test/pipelining/Yjava-tasty-paths/a/InnerClassSub.java b/sbt-test/pipelining/Yjava-tasty-paths/a/InnerClassSub.java new file mode 100644 index 000000000000..6441d71a4b20 --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-paths/a/InnerClassSub.java @@ -0,0 +1,52 @@ +package a; + +public class InnerClassSub extends InnerClass { + + public class InnerSub extends Inner { + public InnerSub(U innerField) { + super(innerField); + } + } + + public class OuterSub extends Outer { + public OuterSub() { + super(); + } + } + + public Inner createInnerSub(U innerField) { + return new InnerSub<>(innerField); + } + + public Outer.Nested createNestedSub(U outerField, V innerField) { + OuterSub outer = new OuterSub<>(); + return outer.new Nested<>(outerField, innerField); + } + + public InnerClass.Inner createInnerSub2(U innerField) { + return new InnerSub<>(innerField); + } + + public InnerClass.Outer.Nested createNestedSub2(U outerField, V innerField) { + OuterSub outer = new OuterSub<>(); + return outer.new Nested<>(outerField, innerField); + } + + public static InnerClass.Inner createInnerStatic(U innerField) { + InnerClassSub innerClass = new InnerClassSub(); + return innerClass.new Inner<>(innerField); + } + + public static InnerClass.Outer.Nested createNestedStatic(U outerField, V innerField) { + InnerClassSub innerClass = new InnerClassSub(); + InnerClassSub.Outer outer = innerClass.new Outer<>(); + return outer.new Nested<>(outerField, innerField); + } + + public static void consumeNestedStatic(InnerClass.Outer.Nested nested) { + } + + public static void consumeNestedStatic2(Outer.Nested nested) { + } + +} diff --git a/sbt-test/pipelining/Yjava-tasty-paths/a/RawTypes.java b/sbt-test/pipelining/Yjava-tasty-paths/a/RawTypes.java new file mode 100644 index 000000000000..4f97c45e7f90 --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-paths/a/RawTypes.java @@ -0,0 +1,16 @@ +package a; + +public class RawTypes { + + public class C { + public class D { + } + } + + public static void mii_Raw_Raw(RawTypes.C.D d) { + } + + public static void mii_Raw_Raw2(C.D d) { + } + +} diff --git a/sbt-test/pipelining/Yjava-tasty-paths/a/package.scala b/sbt-test/pipelining/Yjava-tasty-paths/a/package.scala new file mode 100644 index 000000000000..93f99e9892fe --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-paths/a/package.scala @@ -0,0 +1,2 @@ +// THIS FILE EXISTS SO THAT `A.java` WILL BE COMPILED BY SCALAC +package a diff --git a/sbt-test/pipelining/Yjava-tasty-paths/b/Test.scala b/sbt-test/pipelining/Yjava-tasty-paths/b/Test.scala new file mode 100644 index 000000000000..bad55e361aa7 --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-paths/b/Test.scala @@ -0,0 +1,68 @@ +package b + +import a.InnerClass +import a.InnerClassGen +import a.RawTypes +import a.InnerClassSub + +object B { + @main def test = { + locally { + val ici: InnerClass = new InnerClass() + // val ici_inner1: ici.Inner[Long] = ici.createInner[Long](47L) // error + val ici_inner2: InnerClass#Inner[Long] = ici.createInner[Long](47L) + val ici_inner3: InnerClass#Inner[Long] = InnerClass.createInnerStatic[Long](47L) + + val ici_outer: InnerClass#Outer[Long] = new ici.Outer[Long]() + val ici_nested1: InnerClass#Outer[Long]#Nested[Int] = new ici_outer.Nested[Int](47L, 23) + val ici_nested2: InnerClass#Outer[Long]#Nested[Int] = ici.createNested[Long, Int](47L, 23) + val ici_nested3: InnerClass#Outer[Long]#Nested[Int] = InnerClass.createNestedStatic[Long, Int](47L, 23) + + InnerClass.consumeNestedStatic(ici_nested3) + InnerClass.consumeNestedStatic2(ici_nested3) + } + + locally { + val ici: InnerClassGen[String] = new InnerClassGen() + // val ici_inner1: ici.Inner[Long] = ici.createInner[Long]("Hello", 47L) // error + val ici_inner2: InnerClassGen[String]#Inner[Long] = ici.createInner[Long]("Hello", 47L) + val ici_inner3: InnerClassGen[String]#Inner[Long] = InnerClassGen.createInnerStatic[String, Long]("Hello", 47L) + + val ici_outer: InnerClassGen[String]#Outer[Long] = new ici.Outer[Long]() + val ici_nested1: InnerClassGen[String]#Outer[Long]#Nested[Int] = new ici_outer.Nested[Int]("Hello", 47L, 23) + val ici_nested2: InnerClassGen[String]#Outer[Long]#Nested[Int] = ici.createNested[Long, Int]("Hello", 47L, 23) + val ici_nested3: InnerClassGen[String]#Outer[Long]#Nested[Int] = InnerClassGen.createNestedStatic[String, Long, Int]("Hello", 47L, 23) + + InnerClassGen.consumeNestedStatic(ici_nested3) + } + + locally { + val rt: RawTypes = new RawTypes() + val c: RawTypes#C[String] = new rt.C[String]() + + val cd_ii: RawTypes#C[String]#D[String] = new c.D[String]() + val cd_ii_Raw: RawTypes#C[?]#D[?] = cd_ii + + 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) + } + } + +} diff --git a/sbt-test/pipelining/Yjava-tasty-paths/build.sbt b/sbt-test/pipelining/Yjava-tasty-paths/build.sbt new file mode 100644 index 000000000000..d63d1f9a3f7e --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-paths/build.sbt @@ -0,0 +1,31 @@ +lazy val a = project.in(file("a")) + .settings( + scalacOptions += "-Yjava-tasty", // enable pickling of java signatures + scalacOptions ++= Seq("-Yjava-tasty-output", ((ThisBuild / baseDirectory).value / "a-paths-java-tasty.jar").toString), + scalacOptions += "-Ycheck:all", + Compile / classDirectory := ((ThisBuild / baseDirectory).value / "a-paths-classes"), // send classfiles to a different directory + ) + +lazy val b = project.in(file("b")) + .settings( + Compile / unmanagedClasspath := Seq(Attributed.blank((ThisBuild / baseDirectory).value / "a-paths-java-tasty.jar")), + scalacOptions += "-Ycheck:all", + scalacOptions += "-explain-cyclic", + scalacOptions += "-Ydebug-cyclic", + ) + .settings( + fork := true, // we have to fork the JVM if we actually want to run the code with correct failure semantics + Runtime / unmanagedClasspath += Attributed.blank((ThisBuild / baseDirectory).value / "a-paths-classes"), // make sure the java classes are visible at runtime + ) + +// same as b, but adds the real classes to the classpath instead of the tasty jar +lazy val bAlt = project.in(file("b-alt")) + .settings( + Compile / sources := (b / Compile / sources).value, + Compile / unmanagedClasspath := Seq(Attributed.blank((ThisBuild / baseDirectory).value / "a-paths-classes")), + scalacOptions += "-Ycheck:all", + ) + .settings( + fork := true, // we have to fork the JVM if we actually want to run the code with correct failure semantics + Runtime / unmanagedClasspath += Attributed.blank((ThisBuild / baseDirectory).value / "a-paths-classes"), // make sure the java classes are visible at runtime + ) diff --git a/sbt-test/pipelining/Yjava-tasty-paths/project/DottyInjectedPlugin.scala b/sbt-test/pipelining/Yjava-tasty-paths/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..69f15d168bfc --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-paths/project/DottyInjectedPlugin.scala @@ -0,0 +1,12 @@ +import sbt._ +import Keys._ + +object DottyInjectedPlugin extends AutoPlugin { + override def requires = plugins.JvmPlugin + override def trigger = allRequirements + + override val projectSettings = Seq( + scalaVersion := sys.props("plugin.scalaVersion"), + scalacOptions += "-source:3.0-migration" + ) +} diff --git a/sbt-test/pipelining/Yjava-tasty-paths/test b/sbt-test/pipelining/Yjava-tasty-paths/test new file mode 100644 index 000000000000..101a1b7cd2f1 --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-paths/test @@ -0,0 +1,5 @@ +> a/compile +# test depending on variations of Java paths +> b/run +# double check against the real java classes +> bAlt/run diff --git a/tests/neg/i19619/InnerClass.java b/tests/neg/i19619/InnerClass.java new file mode 100644 index 000000000000..32bb1642a232 --- /dev/null +++ b/tests/neg/i19619/InnerClass.java @@ -0,0 +1,67 @@ +// InnerClass.java + +package lib; + +public class InnerClass { + + public class Inner { + public U innerField; + + public Inner(U innerField) { + this.innerField = innerField; + } + + public U getInnerField() { + return innerField; + } + } + + public class Outer { + + public class Nested { + + public U outerField; + public V innerField; + + public Nested(U outerField, V innerField) { + this.outerField = outerField; + this.innerField = innerField; + } + + public U getOuterField() { + return outerField; + } + + public V getInnerField() { + return innerField; + } + } + } + + public Inner createInner(U innerField) { + return new Inner<>(innerField); + } + + public Outer.Nested createNested(U outerField, V innerField) { + Outer outer = new Outer<>(); + return outer.new Nested<>(outerField, innerField); + } + + public static InnerClass.Inner createInnerStatic(U innerField) { + InnerClass innerClass = new InnerClass(); + return innerClass.new Inner<>(innerField); + } + + public static InnerClass.Outer.Nested createNestedStatic(U outerField, V innerField) { + InnerClass innerClass = new InnerClass(); + InnerClass.Outer outer = innerClass.new Outer<>(); + return outer.new Nested<>(outerField, innerField); + } + + public static void consumeNestedStatic(InnerClass.Outer.Nested nested) { + } + + public static void consumeNestedStatic2(Outer.Nested nested) { + } + +} diff --git a/tests/neg/i19619/InnerClassGen.java b/tests/neg/i19619/InnerClassGen.java new file mode 100644 index 000000000000..3a691aa0608f --- /dev/null +++ b/tests/neg/i19619/InnerClassGen.java @@ -0,0 +1,80 @@ +// InnerClassGen.java + +package lib; + +public class InnerClassGen { + + public class Inner { + public T rootField; + public U innerField; + + public Inner(T rootField, U innerField) { + this.rootField = rootField; + this.innerField = innerField; + } + + public T getRootField() { + return rootField; + } + + public U getInnerField() { + return innerField; + } + } + + public class Outer { + + public class Nested { + public T rootField; + public U outerField; + public V innerField; + + public Nested(T rootField, U outerField, V innerField) { + this.rootField = rootField; + this.outerField = outerField; + this.innerField = innerField; + } + + public T getRootField() { + return rootField; + } + + public U getOuterField() { + return outerField; + } + + public V getInnerField() { + return innerField; + } + } + } + + public static class OuterStatic { + public static class NestedStatic { + } + } + + public Inner createInner(T rootField, U innerField) { + return new Inner<>(rootField, innerField); + } + + public Outer.Nested createNested(T rootField, U outerField, V innerField) { + Outer outer = new Outer<>(); + return outer.new Nested<>(rootField, outerField, innerField); + } + + public static InnerClassGen.Inner createInnerStatic(T rootField, U innerField) { + InnerClassGen innerClassGen = new InnerClassGen<>(); + return innerClassGen.new Inner<>(rootField, innerField); + } + + public static InnerClassGen.Outer.Nested createNestedStatic(T rootField, U outerField, V innerField) { + InnerClassGen innerClassGen = new InnerClassGen<>(); + InnerClassGen.Outer outer = innerClassGen.new Outer<>(); + return outer.new Nested<>(rootField, outerField, innerField); + } + + public static void consumeNestedStatic(InnerClassGen.Outer.Nested nested) { + } + +} diff --git a/tests/neg/i19619/Test.scala b/tests/neg/i19619/Test.scala new file mode 100644 index 000000000000..85f9b3e529ac --- /dev/null +++ b/tests/neg/i19619/Test.scala @@ -0,0 +1,12 @@ +import lib.InnerClass +import lib.InnerClassGen + +@main def Test = + + locally: + val ici: InnerClass = new InnerClass() + val ici_inner1: ici.Inner[Long] = ici.createInner[Long](47L) // error + + locally: + val ici: InnerClassGen[String] = new InnerClassGen() + val ici_inner1: ici.Inner[Long] = ici.createInner[Long]("Hello", 47L) // error diff --git a/tests/run/i19619/InnerClass.java b/tests/run/i19619/InnerClass.java new file mode 100644 index 000000000000..32bb1642a232 --- /dev/null +++ b/tests/run/i19619/InnerClass.java @@ -0,0 +1,67 @@ +// InnerClass.java + +package lib; + +public class InnerClass { + + public class Inner { + public U innerField; + + public Inner(U innerField) { + this.innerField = innerField; + } + + public U getInnerField() { + return innerField; + } + } + + public class Outer { + + public class Nested { + + public U outerField; + public V innerField; + + public Nested(U outerField, V innerField) { + this.outerField = outerField; + this.innerField = innerField; + } + + public U getOuterField() { + return outerField; + } + + public V getInnerField() { + return innerField; + } + } + } + + public Inner createInner(U innerField) { + return new Inner<>(innerField); + } + + public Outer.Nested createNested(U outerField, V innerField) { + Outer outer = new Outer<>(); + return outer.new Nested<>(outerField, innerField); + } + + public static InnerClass.Inner createInnerStatic(U innerField) { + InnerClass innerClass = new InnerClass(); + return innerClass.new Inner<>(innerField); + } + + public static InnerClass.Outer.Nested createNestedStatic(U outerField, V innerField) { + InnerClass innerClass = new InnerClass(); + InnerClass.Outer outer = innerClass.new Outer<>(); + return outer.new Nested<>(outerField, innerField); + } + + public static void consumeNestedStatic(InnerClass.Outer.Nested nested) { + } + + public static void consumeNestedStatic2(Outer.Nested nested) { + } + +} diff --git a/tests/run/i19619/InnerClassGen.java b/tests/run/i19619/InnerClassGen.java new file mode 100644 index 000000000000..3a691aa0608f --- /dev/null +++ b/tests/run/i19619/InnerClassGen.java @@ -0,0 +1,80 @@ +// InnerClassGen.java + +package lib; + +public class InnerClassGen { + + public class Inner { + public T rootField; + public U innerField; + + public Inner(T rootField, U innerField) { + this.rootField = rootField; + this.innerField = innerField; + } + + public T getRootField() { + return rootField; + } + + public U getInnerField() { + return innerField; + } + } + + public class Outer { + + public class Nested { + public T rootField; + public U outerField; + public V innerField; + + public Nested(T rootField, U outerField, V innerField) { + this.rootField = rootField; + this.outerField = outerField; + this.innerField = innerField; + } + + public T getRootField() { + return rootField; + } + + public U getOuterField() { + return outerField; + } + + public V getInnerField() { + return innerField; + } + } + } + + public static class OuterStatic { + public static class NestedStatic { + } + } + + public Inner createInner(T rootField, U innerField) { + return new Inner<>(rootField, innerField); + } + + public Outer.Nested createNested(T rootField, U outerField, V innerField) { + Outer outer = new Outer<>(); + return outer.new Nested<>(rootField, outerField, innerField); + } + + public static InnerClassGen.Inner createInnerStatic(T rootField, U innerField) { + InnerClassGen innerClassGen = new InnerClassGen<>(); + return innerClassGen.new Inner<>(rootField, innerField); + } + + public static InnerClassGen.Outer.Nested createNestedStatic(T rootField, U outerField, V innerField) { + InnerClassGen innerClassGen = new InnerClassGen<>(); + InnerClassGen.Outer outer = innerClassGen.new Outer<>(); + return outer.new Nested<>(rootField, outerField, innerField); + } + + public static void consumeNestedStatic(InnerClassGen.Outer.Nested nested) { + } + +} diff --git a/tests/run/i19619/InnerClassSub.java b/tests/run/i19619/InnerClassSub.java new file mode 100644 index 000000000000..5a1d1f4d3857 --- /dev/null +++ b/tests/run/i19619/InnerClassSub.java @@ -0,0 +1,54 @@ +// InnerClass.java + +package lib; + +public class InnerClassSub extends InnerClass { + + public class InnerSub extends Inner { + public InnerSub(U innerField) { + super(innerField); + } + } + + public class OuterSub extends Outer { + public OuterSub() { + super(); + } + } + + public Inner createInnerSub(U innerField) { + return new InnerSub<>(innerField); + } + + public Outer.Nested createNestedSub(U outerField, V innerField) { + OuterSub outer = new OuterSub<>(); + return outer.new Nested<>(outerField, innerField); + } + + public InnerClass.Inner createInnerSub2(U innerField) { + return new InnerSub<>(innerField); + } + + public InnerClass.Outer.Nested createNestedSub2(U outerField, V innerField) { + OuterSub outer = new OuterSub<>(); + return outer.new Nested<>(outerField, innerField); + } + + public static InnerClass.Inner createInnerStatic(U innerField) { + InnerClassSub innerClass = new InnerClassSub(); + return innerClass.new Inner<>(innerField); + } + + public static InnerClass.Outer.Nested createNestedStatic(U outerField, V innerField) { + InnerClassSub innerClass = new InnerClassSub(); + InnerClassSub.Outer outer = innerClass.new Outer<>(); + return outer.new Nested<>(outerField, innerField); + } + + public static void consumeNestedStatic(InnerClass.Outer.Nested nested) { + } + + public static void consumeNestedStatic2(Outer.Nested nested) { + } + +} diff --git a/tests/run/i19619/RawTypes.java b/tests/run/i19619/RawTypes.java new file mode 100644 index 000000000000..4373a04093eb --- /dev/null +++ b/tests/run/i19619/RawTypes.java @@ -0,0 +1,18 @@ +// RawTypes.java + +package lib; + +public class RawTypes { + + public class C { + public class D { + } + } + + public static void mii_Raw_Raw(RawTypes.C.D d) { + } + + public static void mii_Raw_Raw2(C.D d) { + } + +} diff --git a/tests/run/i19619/Test.scala b/tests/run/i19619/Test.scala new file mode 100644 index 000000000000..871e7a490ea0 --- /dev/null +++ b/tests/run/i19619/Test.scala @@ -0,0 +1,61 @@ +// scalajs: --skip + +import lib.InnerClass +import lib.InnerClassGen +import lib.RawTypes +import lib.InnerClassSub + +@main def Test = + + locally: + val ici: InnerClass = new InnerClass() + // val ici_inner1: ici.Inner[Long] = ici.createInner[Long](47L) // error + val ici_inner2: InnerClass#Inner[Long] = ici.createInner[Long](47L) + val ici_inner3: InnerClass#Inner[Long] = InnerClass.createInnerStatic[Long](47L) + + val ici_outer: InnerClass#Outer[Long] = new ici.Outer[Long]() + val ici_nested1: InnerClass#Outer[Long]#Nested[Int] = new ici_outer.Nested[Int](47L, 23) + val ici_nested2: InnerClass#Outer[Long]#Nested[Int] = ici.createNested[Long, Int](47L, 23) + val ici_nested3: InnerClass#Outer[Long]#Nested[Int] = InnerClass.createNestedStatic[Long, Int](47L, 23) + + InnerClass.consumeNestedStatic(ici_nested3) + InnerClass.consumeNestedStatic2(ici_nested3) + + locally: + val ici: InnerClassGen[String] = new InnerClassGen() + // val ici_inner1: ici.Inner[Long] = ici.createInner[Long]("Hello", 47L) // error + val ici_inner2: InnerClassGen[String]#Inner[Long] = ici.createInner[Long]("Hello", 47L) + val ici_inner3: InnerClassGen[String]#Inner[Long] = InnerClassGen.createInnerStatic[String, Long]("Hello", 47L) + + val ici_outer: InnerClassGen[String]#Outer[Long] = new ici.Outer[Long]() + val ici_nested1: InnerClassGen[String]#Outer[Long]#Nested[Int] = new ici_outer.Nested[Int]("Hello", 47L, 23) + val ici_nested2: InnerClassGen[String]#Outer[Long]#Nested[Int] = ici.createNested[Long, Int]("Hello", 47L, 23) + val ici_nested3: InnerClassGen[String]#Outer[Long]#Nested[Int] = InnerClassGen.createNestedStatic[String, Long, Int]("Hello", 47L, 23) + + InnerClassGen.consumeNestedStatic(ici_nested3) + + locally: + val rt: RawTypes = new RawTypes() + val c: RawTypes#C[String] = new rt.C[String]() + + val cd_ii: RawTypes#C[String]#D[String] = new c.D[String]() + val cd_ii_Raw: RawTypes#C[?]#D[?] = cd_ii + + 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)