Build recursive raw types and raw types which contain type parameters properly

1) Substitute erasure of other type parameters
2) Use star projection at top level for recursive raw types

^KT-46126 Fixed
This commit is contained in:
Victor Petukhov
2021-04-19 23:12:10 +03:00
parent f9d2ca68ce
commit 8dd71ec5c8
35 changed files with 606 additions and 41 deletions
@@ -21142,6 +21142,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/arrays.kt");
}
@Test
@TestMetadata("dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.kt")
public void testDontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.kt");
}
@Test
@TestMetadata("dontSubstituteAnotherErasedTypeArgumentIfRecursive.kt")
public void testDontSubstituteAnotherErasedTypeArgumentIfRecursive() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedTypeArgumentIfRecursive.kt");
}
@Test
@TestMetadata("errorType.kt")
public void testErrorType() throws Exception {
@@ -21232,6 +21244,30 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/starProjectionToRaw.kt");
}
@Test
@TestMetadata("substituteAnotherErasedTypeArgument.kt")
public void testSubstituteAnotherErasedTypeArgument() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteAnotherErasedTypeArgument.kt");
}
@Test
@TestMetadata("substituteOtherErasedDeepTypeArguments.kt")
public void testSubstituteOtherErasedDeepTypeArguments() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteOtherErasedDeepTypeArguments.kt");
}
@Test
@TestMetadata("substituteSeveralOtherErasedDependentTypeArguments.kt")
public void testSubstituteSeveralOtherErasedDependentTypeArguments() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedDependentTypeArguments.kt");
}
@Test
@TestMetadata("substituteSeveralOtherErasedTypeArguments.kt")
public void testSubstituteSeveralOtherErasedTypeArguments() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedTypeArguments.kt");
}
@Test
@TestMetadata("typeEnhancement.kt")
public void testTypeEnhancement() throws Exception {
@@ -285,7 +285,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
return this
}
override fun TypeParameterMarker.doesFormSelfType(selfConstructor: TypeConstructorMarker): Boolean {
override fun TypeParameterMarker.hasRecursiveBounds(selfConstructor: TypeConstructorMarker): Boolean {
require(this is ConeTypeParameterLookupTag)
return this.typeParameterSymbol.fir.bounds.any { typeRef ->
typeRef.coneType.contains { it.typeConstructor() == this.getTypeConstructor() }
@@ -183,7 +183,7 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon
return false
}
override fun TypeParameterMarker.doesFormSelfType(selfConstructor: TypeConstructorMarker): Boolean {
override fun TypeParameterMarker.hasRecursiveBounds(selfConstructor: TypeConstructorMarker): Boolean {
for (i in 0 until this.upperBoundCount()) {
val upperBound = this.getUpperBound(i)
if (upperBound.containsTypeConstructor(selfConstructor) && upperBound.typeConstructor() == selfConstructor) {
@@ -12,5 +12,5 @@ fun <R> choose3(c: Inv<Inv<R>>) {}
fun f(o: Out<Out<*>>, i: In<In<*>>, inv: Inv<Inv<*>>) {
choose1(o)
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER{NI}, TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER{OI}!>choose2<!>(i)
<!TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR{OI}!>choose3<!>(<!TYPE_MISMATCH{NI}!>inv<!>)
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER{OI}, TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR{OI}!>choose3<!>(<!TYPE_MISMATCH!>inv<!>)
}
@@ -28,5 +28,5 @@ abstract class MySettingsListener<S extends MyComparableSettings> {}
fun test() {
val a = MySettings.getSettings()
a.getLinkedProjectsSettings()
a.<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE{OI}, TYPE_INFERENCE_UPPER_BOUND_VIOLATED{OI}, UNRESOLVED_REFERENCE_WRONG_RECEIVER{NI}!>linkedProjectsSettings<!>
a.<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE{OI}, TYPE_INFERENCE_UPPER_BOUND_VIOLATED{OI}!>linkedProjectsSettings<!>
}
@@ -10,5 +10,5 @@ public open class MySettings</*0*/ SS : MySettings<SS!, PS!, L!>!, /*1*/ PS : My
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public open fun getSettings(): MySettings<(raw) MySettings<*, *, *>!, (raw) MyComparableSettings!, (raw) MySettingsListener<*>!>!
public open fun getSettings(): (MySettings<(raw) *, (raw) MyComparableSettings!, (raw) MySettingsListener<MyComparableSettings!>!>..MySettings<*, *, out MySettingsListener<*>!>?)
}
+1 -1
View File
@@ -5,7 +5,7 @@ package a {
public open class C</*0*/ B : a.C<B!>!> {
public constructor C</*0*/ B : a.C<B!>!>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun foo(): a.C<(raw) a.C<*>!>!
public open fun foo(): a.C<(raw) *>!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
@@ -0,0 +1,26 @@
// WITH_RUNTIME
// FULL_JDK
// FILE: X.java
class X<B extends I<P, B>, P> {
static final E<X> E = new E<>();
String getId() {
return null;
}
}
class E<T> {
T getT() {
return null;
}
}
interface I<P, L> {}
// FILE: test.kt
fun test() {
val t = X.E.<!UNRESOLVED_REFERENCE!>t<!>
t
t.<!UNRESOLVED_REFERENCE!>id<!> // should be OK
}
@@ -0,0 +1,26 @@
// WITH_RUNTIME
// FULL_JDK
// FILE: X.java
class X<B extends I<P, B>, P> {
static final E<X> E = new E<>();
String getId() {
return null;
}
}
class E<T> {
T getT() {
return null;
}
}
interface I<P, L> {}
// FILE: test.kt
fun test() {
val t = X.E.t
<!DEBUG_INFO_EXPRESSION_TYPE("(X<*, (kotlin.Any..kotlin.Any?)>..X<*, *>?)")!>t<!>
t.id // should be OK
}
@@ -0,0 +1,14 @@
package
public fun test(): kotlin.Unit
public/*package*/ open class X</*0*/ B : I<P!, B!>!, /*1*/ P : kotlin.Any!> {
public/*package*/ constructor X</*0*/ B : I<P!, B!>!, /*1*/ P : kotlin.Any!>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public/*package*/ open fun getId(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public/*package*/ final val E: E<X<(raw) *, (raw) kotlin.Any!>!>!
}
@@ -0,0 +1,26 @@
// WITH_RUNTIME
// FULL_JDK
// FILE: X.java
class X<B extends I<B>> {
static final E<X> E = new E<>();
String getId() {
return null;
}
}
class E<T> {
T getT() {
return null;
}
}
interface I<P> {}
// FILE: test.kt
fun test() {
val t = X.E.<!UNRESOLVED_REFERENCE!>t<!>
t
t.<!UNRESOLVED_REFERENCE!>id<!> // should be OK
}
@@ -0,0 +1,26 @@
// WITH_RUNTIME
// FULL_JDK
// FILE: X.java
class X<B extends I<B>> {
static final E<X> E = new E<>();
String getId() {
return null;
}
}
class E<T> {
T getT() {
return null;
}
}
interface I<P> {}
// FILE: test.kt
fun test() {
val t = X.E.t
<!DEBUG_INFO_EXPRESSION_TYPE("(X<*>..X<*>?)")!>t<!>
t.id // should be OK
}
@@ -0,0 +1,14 @@
package
public fun test(): kotlin.Unit
public/*package*/ open class X</*0*/ B : I<B!>!> {
public/*package*/ constructor X</*0*/ B : I<B!>!>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public/*package*/ open fun getId(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public/*package*/ final val E: E<X<(raw) *>!>!
}
@@ -0,0 +1,26 @@
// WITH_RUNTIME
// FULL_JDK
// FILE: X.java
class X<B extends I<P>, P> {
static final E<X> E = new E<>();
String getId() {
return null;
}
}
class E<T> {
T getT() {
return null;
}
}
interface I<P> {}
// FILE: test.kt
fun test() {
val t = X.E.<!UNRESOLVED_REFERENCE!>t<!>
t
t.<!UNRESOLVED_REFERENCE!>id<!> // should be OK
}
@@ -0,0 +1,26 @@
// WITH_RUNTIME
// FULL_JDK
// FILE: X.java
class X<B extends I<P>, P> {
static final E<X> E = new E<>();
String getId() {
return null;
}
}
class E<T> {
T getT() {
return null;
}
}
interface I<P> {}
// FILE: test.kt
fun test() {
val t = X.E.t
<!DEBUG_INFO_EXPRESSION_TYPE("(X<(I<(kotlin.Any..kotlin.Any?)>..I<(kotlin.Any..kotlin.Any?)>?), (kotlin.Any..kotlin.Any?)>..X<out (I<*>..I<*>?), *>?)")!>t<!>
t.id // should be OK
}
@@ -0,0 +1,14 @@
package
public fun test(): kotlin.Unit
public/*package*/ open class X</*0*/ B : I<P!>!, /*1*/ P : kotlin.Any!> {
public/*package*/ constructor X</*0*/ B : I<P!>!, /*1*/ P : kotlin.Any!>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public/*package*/ open fun getId(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public/*package*/ final val E: E<(X<(raw) I<kotlin.Any!>!, (raw) kotlin.Any!>..X<out I<*>!, *>?)>!
}
@@ -0,0 +1,27 @@
// WITH_RUNTIME
// FULL_JDK
// FILE: X.java
class X<B extends I1<P, P, P>, P, A extends I1<I2<B>, B, I1<P, I2<B>, P>>> {
static final E<X> E = new E<>();
String getId() {
return null;
}
}
class E<T> {
T getT() {
return null;
}
}
interface I1<P, A, F> {}
interface I2<S> {}
// FILE: test.kt
fun test() {
val t = X.E.<!UNRESOLVED_REFERENCE!>t<!>
t
t.<!UNRESOLVED_REFERENCE!>id<!> // error before
}
@@ -0,0 +1,27 @@
// WITH_RUNTIME
// FULL_JDK
// FILE: X.java
class X<B extends I1<P, P, P>, P, A extends I1<I2<B>, B, I1<P, I2<B>, P>>> {
static final E<X> E = new E<>();
String getId() {
return null;
}
}
class E<T> {
T getT() {
return null;
}
}
interface I1<P, A, F> {}
interface I2<S> {}
// FILE: test.kt
fun test() {
val t = X.E.t
<!DEBUG_INFO_EXPRESSION_TYPE("(X<(I1<(kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?)>..I1<(kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?)>?), (kotlin.Any..kotlin.Any?), (I1<*, (I1<(kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?)>..I1<(kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?)>?), *>..I1<*, (I1<(kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?)>..I1<(kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?)>?), *>?)>..X<out (I1<*, *, *>..I1<*, *, *>?), *, out (I1<*, out (I1<*, *, *>..I1<*, *, *>?), *>..I1<*, out (I1<*, *, *>..I1<*, *, *>?), *>?)>?)")!>t<!>
t.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>id<!> // error before
}
@@ -0,0 +1,14 @@
package
public fun test(): kotlin.Unit
public/*package*/ open class X</*0*/ B : I1<P!, P!, P!>!, /*1*/ P : kotlin.Any!, /*2*/ A : I1<I2<B!>!, B!, I1<P!, I2<B!>!, P!>!>!> {
public/*package*/ constructor X</*0*/ B : I1<P!, P!, P!>!, /*1*/ P : kotlin.Any!, /*2*/ A : I1<I2<B!>!, B!, I1<P!, I2<B!>!, P!>!>!>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public/*package*/ open fun getId(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public/*package*/ final val E: E<(X<(raw) I1<kotlin.Any!, kotlin.Any!, kotlin.Any!>!, (raw) kotlin.Any!, (raw) I1<*, I1<kotlin.Any!, kotlin.Any!, kotlin.Any!>!, *>!>..X<out I1<*, *, *>!, *, out I1<*, out I1<*, *, *>!, *>!>?)>!
}
@@ -0,0 +1,26 @@
// WITH_RUNTIME
// FULL_JDK
// FILE: X.java
class X<B extends I<P>, P, A extends I<B>> {
static final E<X> E = new E<>();
String getId() {
return null;
}
}
class E<T> {
T getT() {
return null;
}
}
interface I<P> {}
// FILE: test.kt
fun test() {
val t = X.E.<!UNRESOLVED_REFERENCE!>t<!>
t
t.<!UNRESOLVED_REFERENCE!>id<!> // should be OK
}
@@ -0,0 +1,26 @@
// WITH_RUNTIME
// FULL_JDK
// FILE: X.java
class X<B extends I<P>, P, A extends I<B>> {
static final E<X> E = new E<>();
String getId() {
return null;
}
}
class E<T> {
T getT() {
return null;
}
}
interface I<P> {}
// FILE: test.kt
fun test() {
val t = X.E.t
<!DEBUG_INFO_EXPRESSION_TYPE("(X<(I<(kotlin.Any..kotlin.Any?)>..I<(kotlin.Any..kotlin.Any?)>?), (kotlin.Any..kotlin.Any?), (I<(I<(kotlin.Any..kotlin.Any?)>..I<(kotlin.Any..kotlin.Any?)>?)>..I<(I<(kotlin.Any..kotlin.Any?)>..I<(kotlin.Any..kotlin.Any?)>?)>?)>..X<out (I<*>..I<*>?), *, out (I<out (I<*>..I<*>?)>..I<out (I<*>..I<*>?)>?)>?)")!>t<!>
t.id // should be OK
}
@@ -0,0 +1,14 @@
package
public fun test(): kotlin.Unit
public/*package*/ open class X</*0*/ B : I<P!>!, /*1*/ P : kotlin.Any!, /*2*/ A : I<B!>!> {
public/*package*/ constructor X</*0*/ B : I<P!>!, /*1*/ P : kotlin.Any!, /*2*/ A : I<B!>!>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public/*package*/ open fun getId(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public/*package*/ final val E: E<(X<(raw) I<kotlin.Any!>!, (raw) kotlin.Any!, (raw) I<I<kotlin.Any!>!>!>..X<out I<*>!, *, out I<out I<*>!>!>?)>!
}
@@ -0,0 +1,26 @@
// WITH_RUNTIME
// FULL_JDK
// FILE: X.java
class X<B extends I<P>, P, A extends I<P>> {
static final E<X> E = new E<>();
String getId() {
return null;
}
}
class E<T> {
T getT() {
return null;
}
}
interface I<P> {}
// FILE: test.kt
fun test() {
val t = X.E.<!UNRESOLVED_REFERENCE!>t<!>
t
t.<!UNRESOLVED_REFERENCE!>id<!> // should be OK
}
@@ -0,0 +1,26 @@
// WITH_RUNTIME
// FULL_JDK
// FILE: X.java
class X<B extends I<P>, P, A extends I<P>> {
static final E<X> E = new E<>();
String getId() {
return null;
}
}
class E<T> {
T getT() {
return null;
}
}
interface I<P> {}
// FILE: test.kt
fun test() {
val t = X.E.t
<!DEBUG_INFO_EXPRESSION_TYPE("(X<(I<(kotlin.Any..kotlin.Any?)>..I<(kotlin.Any..kotlin.Any?)>?), (kotlin.Any..kotlin.Any?), (I<(kotlin.Any..kotlin.Any?)>..I<(kotlin.Any..kotlin.Any?)>?)>..X<out (I<*>..I<*>?), *, out (I<*>..I<*>?)>?)")!>t<!>
t.id // should be OK
}
@@ -0,0 +1,14 @@
package
public fun test(): kotlin.Unit
public/*package*/ open class X</*0*/ B : I<P!>!, /*1*/ P : kotlin.Any!, /*2*/ A : I<P!>!> {
public/*package*/ constructor X</*0*/ B : I<P!>!, /*1*/ P : kotlin.Any!, /*2*/ A : I<P!>!>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public/*package*/ open fun getId(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public/*package*/ final val E: E<(X<(raw) I<kotlin.Any!>!, (raw) kotlin.Any!, (raw) I<kotlin.Any!>!>..X<out I<*>!, *, out I<*>!>?)>!
}
@@ -3,11 +3,11 @@ package test
public open class RawSuperTypeWithRecursiveBound {
public constructor RawSuperTypeWithRecursiveBound()
public open inner class Derived : test.RawSuperTypeWithRecursiveBound.Super<(raw) test.RawSuperTypeWithRecursiveBound.Super<*>!> {
public open inner class Derived : test.RawSuperTypeWithRecursiveBound.Super<(raw) *> {
public constructor Derived()
public open override /*1*/ fun dummy(): kotlin.Unit
public open fun foo(/*0*/ p0: kotlin.Any!): kotlin.Unit
public open override /*1*/ fun foo(/*0*/ p0: test.RawSuperTypeWithRecursiveBound.Super<(raw) test.RawSuperTypeWithRecursiveBound.Super<*>!>!): kotlin.Unit
public open override /*1*/ fun foo(/*0*/ p0: test.RawSuperTypeWithRecursiveBound.Super<(raw) *>!): kotlin.Unit
}
public interface Super</*0*/ T : test.RawSuperTypeWithRecursiveBound.Super<T!>!> {
@@ -3,11 +3,11 @@ package test
public open class RawSuperTypeWithRecursiveBoundMultipleParameters {
public constructor RawSuperTypeWithRecursiveBoundMultipleParameters()
public open inner class Derived : test.RawSuperTypeWithRecursiveBoundMultipleParameters.Super<(raw) kotlin.Any!, (raw) test.RawSuperTypeWithRecursiveBoundMultipleParameters.Super<*, *>!> {
public open inner class Derived : test.RawSuperTypeWithRecursiveBoundMultipleParameters.Super<(raw) kotlin.Any!, (raw) *> {
public constructor Derived()
public open override /*1*/ fun dummy(): kotlin.Unit
public open fun foo(/*0*/ p0: kotlin.Any!, /*1*/ p1: kotlin.Any!): kotlin.Unit
public open override /*1*/ fun foo(/*0*/ p0: kotlin.Any!, /*1*/ p1: test.RawSuperTypeWithRecursiveBoundMultipleParameters.Super<(raw) kotlin.Any!, (raw) test.RawSuperTypeWithRecursiveBoundMultipleParameters.Super<*, *>!>!): kotlin.Unit
public open override /*1*/ fun foo(/*0*/ p0: kotlin.Any!, /*1*/ p1: test.RawSuperTypeWithRecursiveBoundMultipleParameters.Super<(raw) kotlin.Any!, (raw) *>!): kotlin.Unit
}
public interface Super</*0*/ R : kotlin.Any!, /*1*/ T : test.RawSuperTypeWithRecursiveBoundMultipleParameters.Super<R!, T!>!> {
@@ -21148,6 +21148,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/arrays.kt");
}
@Test
@TestMetadata("dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.kt")
public void testDontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.kt");
}
@Test
@TestMetadata("dontSubstituteAnotherErasedTypeArgumentIfRecursive.kt")
public void testDontSubstituteAnotherErasedTypeArgumentIfRecursive() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedTypeArgumentIfRecursive.kt");
}
@Test
@TestMetadata("errorType.kt")
public void testErrorType() throws Exception {
@@ -21238,6 +21250,30 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/starProjectionToRaw.kt");
}
@Test
@TestMetadata("substituteAnotherErasedTypeArgument.kt")
public void testSubstituteAnotherErasedTypeArgument() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteAnotherErasedTypeArgument.kt");
}
@Test
@TestMetadata("substituteOtherErasedDeepTypeArguments.kt")
public void testSubstituteOtherErasedDeepTypeArguments() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteOtherErasedDeepTypeArguments.kt");
}
@Test
@TestMetadata("substituteSeveralOtherErasedDependentTypeArguments.kt")
public void testSubstituteSeveralOtherErasedDependentTypeArguments() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedDependentTypeArguments.kt");
}
@Test
@TestMetadata("substituteSeveralOtherErasedTypeArguments.kt")
public void testSubstituteSeveralOtherErasedTypeArguments() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedTypeArguments.kt");
}
@Test
@TestMetadata("typeEnhancement.kt")
public void testTypeEnhancement() throws Exception {
@@ -375,7 +375,7 @@ object AbstractTypeChecker {
val typeVariableConstructor = superArgumentType.typeConstructor() as? TypeVariableTypeConstructorMarker ?: return false
return typeVariableConstructor.typeParameter?.doesFormSelfType(selfConstructor) == true
return typeVariableConstructor.typeParameter?.hasRecursiveBounds(selfConstructor) == true
}
fun AbstractTypeCheckerContext.isSubtypeForSameConstructor(
@@ -506,7 +506,7 @@ object AbstractTypeChecker {
if (subType is CapturedTypeMarker) {
val typeParameter =
context.typeSystemContext.getTypeParameterForArgumentInBaseIfItEqualToTarget(baseType = superType, targetType = subType)
if (typeParameter != null && typeParameter.doesFormSelfType(superType.typeConstructor())) {
if (typeParameter != null && typeParameter.hasRecursiveBounds(superType.typeConstructor())) {
return true
}
}
@@ -313,7 +313,7 @@ interface TypeSystemContext : TypeSystemOptimizationContext {
fun TypeParameterMarker.upperBoundCount(): Int
fun TypeParameterMarker.getUpperBound(index: Int): KotlinTypeMarker
fun TypeParameterMarker.getTypeConstructor(): TypeConstructorMarker
fun TypeParameterMarker.doesFormSelfType(selfConstructor: TypeConstructorMarker): Boolean
fun TypeParameterMarker.hasRecursiveBounds(selfConstructor: TypeConstructorMarker): Boolean
fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean
@@ -32,8 +32,7 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.Variance.*
import org.jetbrains.kotlin.types.typeUtil.createProjection
import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
import org.jetbrains.kotlin.types.typeUtil.*
import org.jetbrains.kotlin.utils.sure
private val JAVA_LANG_CLASS_FQ_NAME: FqName = FqName("java.lang.Class")
@@ -210,6 +209,15 @@ class JavaTypeResolver(
val typeParameters = constructor.parameters
if (eraseTypeParameters) {
return typeParameters.map { parameter ->
/*
* We shouldn't erase recursive type parameters to avoid creating types unsatisfying upper bounds.
* E.g. if we got erased raw type of `class Foo<T: Foo<T>> {}` we'd create Foo<(raw) Foo<*>!>!,
* but it's wrong because Foo<*> isn't subtype of Foo<Foo<*>> in accordance with declared upper bound of Foo.
* So we should create Foo<*> in this case (CapturedType(*) is really subtype of Foo<CapturedType(*)>).
*/
if (hasTypeParameterRecursiveBounds(parameter, selfConstructor = null, attr.upperBoundOfTypeParameter))
return@map StarProjectionImpl(parameter)
// Some activity for preventing recursion in cases like `class A<T extends A, F extends T>`
//
// When calculating upper bound of some parameter (attr.upperBoundOfTypeParameter),
@@ -222,12 +230,11 @@ class JavaTypeResolver(
// - Calculating second argument for raw upper bound of T. It depends on F, that again depends on upper bound of T,
// so we get A<*, *>.
// Summary result for upper bound of T is `A<A<*, *>, A<*, *>>..A<out A<*, *>, out A<*, *>>`
val erasedUpperBound =
LazyWrappedType(c.storageManager) {
parameter.getErasedUpperBound(attr.upperBoundOfTypeParameter) {
constructor.declarationDescriptor!!.defaultType.replaceArgumentsWithStarProjections()
}
val erasedUpperBound = LazyWrappedType(c.storageManager) {
parameter.getErasedUpperBound(isRaw, attr) {
constructor.declarationDescriptor!!.defaultType.replaceArgumentsWithStarProjections()
}
}
RawSubstitution.computeProjection(
parameter,
@@ -333,24 +340,51 @@ internal fun TypeParameterDescriptor.getErasedUpperBound(
// Calculation of `potentiallyRecursiveTypeParameter.upperBounds` may recursively depend on `this.getErasedUpperBound`
// E.g. `class A<T extends A, F extends A>`
// To prevent recursive calls return defaultValue() instead
potentiallyRecursiveTypeParameter: TypeParameterDescriptor? = null,
isRaw: Boolean,
typeAttr: JavaTypeAttributes,
defaultValue: (() -> KotlinType) = { ErrorUtils.createErrorType("Can't compute erased upper bound of type parameter `$this`") }
): KotlinType {
if (this === potentiallyRecursiveTypeParameter) return defaultValue()
if (this === typeAttr.upperBoundOfTypeParameter) return defaultValue()
/*
* We should do erasure of containing type parameters with their erasure to avoid creating inconsistent types.
* E.g. for `class Foo<T: Foo<B>, B>`, we'd have erasure for lower bound: Foo<Foo<*>, Any>,
* but it's wrong type: projection(*) != projection(Any).
* So we should substitute erasure of the corresponding type parameter: `Foo<Foo<Any>, Any>` or `Foo<Foo<*>, *>`.
*/
val erasedUpperBounds = defaultType.extractTypeParametersFromUpperBounds(typeAttr.upperBoundOfTypeParameter).associate {
it.typeConstructor to RawSubstitution.computeProjection(
this,
// if erasure happens due to invalid arguments number, use star projections instead
if (isRaw) typeAttr else typeAttr.withFlexibility(INFLEXIBLE),
it.getErasedUpperBound(isRaw, typeAttr)
)
}
val erasedUpperBoundsSubstitutor = TypeSubstitutor.create(TypeConstructorSubstitution.createByConstructorsMap(erasedUpperBounds))
val firstUpperBound = upperBounds.first()
if (firstUpperBound.constructor.declarationDescriptor is ClassDescriptor) {
return firstUpperBound.replaceArgumentsWithStarProjections()
return firstUpperBound.replaceArgumentsWithStarProjectionOrMapped(
erasedUpperBoundsSubstitutor,
erasedUpperBounds,
OUT_VARIANCE,
typeAttr.upperBoundOfTypeParameter
)
}
val stopAt = potentiallyRecursiveTypeParameter ?: this
val stopAt = typeAttr.upperBoundOfTypeParameter ?: this
var current = firstUpperBound.constructor.declarationDescriptor as TypeParameterDescriptor
while (current != stopAt) {
val nextUpperBound = current.upperBounds.first()
if (nextUpperBound.constructor.declarationDescriptor is ClassDescriptor) {
return nextUpperBound.replaceArgumentsWithStarProjections()
return nextUpperBound.replaceArgumentsWithStarProjectionOrMapped(
erasedUpperBoundsSubstitutor,
erasedUpperBounds,
OUT_VARIANCE,
typeAttr.upperBoundOfTypeParameter
)
}
current = nextUpperBound.constructor.declarationDescriptor as TypeParameterDescriptor
@@ -107,10 +107,9 @@ internal object RawSubstitution : TypeSubstitution() {
private val lowerTypeAttr = TypeUsage.COMMON.toAttributes().withFlexibility(JavaTypeFlexibility.FLEXIBLE_LOWER_BOUND)
private val upperTypeAttr = TypeUsage.COMMON.toAttributes().withFlexibility(JavaTypeFlexibility.FLEXIBLE_UPPER_BOUND)
private fun eraseType(type: KotlinType): KotlinType {
val declaration = type.constructor.declarationDescriptor
return when (declaration) {
is TypeParameterDescriptor -> eraseType(declaration.getErasedUpperBound())
private fun eraseType(type: KotlinType, attr: JavaTypeAttributes = JavaTypeAttributes(TypeUsage.COMMON)): KotlinType {
return when (val declaration = type.constructor.declarationDescriptor) {
is TypeParameterDescriptor -> eraseType(declaration.getErasedUpperBound(isRaw = true, attr), attr)
is ClassDescriptor -> {
val declarationForUpper =
type.upperIfFlexible().constructor.declarationDescriptor
@@ -142,7 +141,7 @@ internal object RawSubstitution : TypeSubstitution() {
if (KotlinBuiltIns.isArray(type)) {
val componentTypeProjection = type.arguments[0]
val arguments = listOf(
TypeProjectionImpl(componentTypeProjection.projectionKind, eraseType(componentTypeProjection.type))
TypeProjectionImpl(componentTypeProjection.projectionKind, eraseType(componentTypeProjection.type, attr))
)
return KotlinTypeFactory.simpleType(
type.annotations, type.constructor, arguments, type.isMarkedNullable
@@ -171,7 +170,7 @@ internal object RawSubstitution : TypeSubstitution() {
fun computeProjection(
parameter: TypeParameterDescriptor,
attr: JavaTypeAttributes,
erasedUpperBound: KotlinType = parameter.getErasedUpperBound()
erasedUpperBound: KotlinType = parameter.getErasedUpperBound(isRaw = true, attr)
) = when (attr.flexibility) {
// Raw(List<T>) => (List<Any?>..List<*>)
// Raw(Enum<T>) => (Enum<Enum<*>>..Enum<out Enum<*>>)
@@ -185,7 +185,74 @@ fun KotlinType.contains(predicate: (UnwrappedType) -> Boolean) = TypeUtils.conta
fun KotlinType.replaceArgumentsWithStarProjections() = replaceArgumentsWith(::StarProjectionImpl)
fun KotlinType.replaceArgumentsWithNothing() = replaceArgumentsWith { it.builtIns.nothingType.asTypeProjection() }
private inline fun KotlinType.replaceArgumentsWith(replacement: (TypeParameterDescriptor) -> TypeProjection): KotlinType {
fun KotlinType.extractTypeParametersFromUpperBounds(upperBoundOfTypeParameter: TypeParameterDescriptor?): Set<TypeParameterDescriptor> =
mutableSetOf<TypeParameterDescriptor>().also { extractTypeParametersFromUpperBounds(this, it, upperBoundOfTypeParameter) }
private fun KotlinType.extractTypeParametersFromUpperBounds(
baseType: KotlinType,
to: MutableSet<TypeParameterDescriptor>,
upperBoundOfTypeParameter: TypeParameterDescriptor?
) {
val declarationDescriptor = constructor.declarationDescriptor
if (declarationDescriptor is TypeParameterDescriptor) {
if (constructor != baseType.constructor) {
to += declarationDescriptor
} else {
for (upperBound in declarationDescriptor.upperBounds) {
upperBound.extractTypeParametersFromUpperBounds(baseType, to, upperBoundOfTypeParameter)
}
}
} else {
val typeParameters = (constructor.declarationDescriptor as? ClassifierDescriptorWithTypeParameters)?.declaredTypeParameters
for ((i, argument) in arguments.withIndex()) {
val typeParameter = typeParameters?.get(i)
if (argument.isStarProjection || (typeParameter != null && typeParameter == upperBoundOfTypeParameter)) continue
if (argument.type.constructor.declarationDescriptor in to || argument.type.constructor == baseType.constructor) continue
argument.type.extractTypeParametersFromUpperBounds(baseType, to, upperBoundOfTypeParameter)
}
}
}
fun hasTypeParameterRecursiveBounds(
typeParameter: TypeParameterDescriptor,
selfConstructor: TypeConstructor? = null,
upperBoundOfTypeParameter: TypeParameterDescriptor? = null
): Boolean =
typeParameter.upperBounds.any { upperBound ->
upperBound.containsSelfTypeParameter(typeParameter.defaultType.constructor, upperBoundOfTypeParameter)
&& (selfConstructor == null || upperBound.constructor == selfConstructor)
}
private fun KotlinType.containsSelfTypeParameter(
baseConstructor: TypeConstructor,
upperBoundOfTypeParameter: TypeParameterDescriptor?
): Boolean {
if (this.constructor == baseConstructor) return true
val typeParameters = (constructor.declarationDescriptor as? ClassifierDescriptorWithTypeParameters)?.declaredTypeParameters
return arguments.withIndex().any { (i, argument) ->
val typeParameter = typeParameters?.get(i)
if ((typeParameter != null && typeParameter == upperBoundOfTypeParameter) || argument.isStarProjection) return@any false
argument.type.containsSelfTypeParameter(baseConstructor, upperBoundOfTypeParameter)
}
}
fun KotlinType.replaceArgumentsWithStarProjectionOrMapped(
substitutor: TypeSubstitutor,
substitutionMap: Map<TypeConstructor, TypeProjection>,
variance: Variance,
upperBoundOfTypeParameter: TypeParameterDescriptor?
) =
replaceArgumentsWith { typeParameterDescriptor ->
val argument = arguments.getOrNull(typeParameterDescriptor.index)
if (typeParameterDescriptor != upperBoundOfTypeParameter && argument != null && argument.type.constructor in substitutionMap) {
argument
} else StarProjectionImpl(typeParameterDescriptor)
}.let { substitutor.safeSubstitute(it, variance) }
inline fun KotlinType.replaceArgumentsWith(replacement: (TypeParameterDescriptor) -> TypeProjection): KotlinType {
val unwrapped = unwrap()
return when (unwrapped) {
is FlexibleType -> KotlinTypeFactory.flexibleType(
@@ -196,7 +263,7 @@ private inline fun KotlinType.replaceArgumentsWith(replacement: (TypeParameterDe
}.inheritEnhancement(unwrapped)
}
private inline fun SimpleType.replaceArgumentsWith(replacement: (TypeParameterDescriptor) -> TypeProjection): SimpleType {
inline fun SimpleType.replaceArgumentsWith(replacement: (TypeParameterDescriptor) -> TypeProjection): SimpleType {
if (constructor.parameters.isEmpty() || constructor.declarationDescriptor == null) return this
val newArguments = constructor.parameters.map(replacement)
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.types.typeUtil.hasTypeParameterRecursiveBounds
import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.kotlin.types.typeUtil.isSignedOrUnsignedNumberType as classicIsSignedOrUnsignedNumberType
@@ -220,11 +221,11 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy
return this.typeConstructor
}
override fun TypeParameterMarker.doesFormSelfType(selfConstructor: TypeConstructorMarker): Boolean {
override fun TypeParameterMarker.hasRecursiveBounds(selfConstructor: TypeConstructorMarker): Boolean {
require(this is TypeParameterDescriptor, this::errorMessage)
require(selfConstructor is TypeConstructor, this::errorMessage)
return doesTypeParameterFormSelfType(this, selfConstructor)
return hasTypeParameterRecursiveBounds(this, selfConstructor)
}
override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean {
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.calls.inference.wrapWithCapturingSubstitution
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.types.typesApproximation.approximateCapturedTypes
import java.util.*
@@ -106,8 +105,3 @@ private fun TypeConstructor.debugInfo() = buildString {
interface NewTypeVariableConstructor {
val originalTypeParameter: TypeParameterDescriptor?
}
fun doesTypeParameterFormSelfType(typeParameter: TypeParameterDescriptor, selfConstructor: TypeConstructor) =
typeParameter.upperBounds.any { upperBound ->
upperBound.contains { it.constructor == typeParameter.typeConstructor } && upperBound.constructor == selfConstructor
}