[NI] Fix issues with star projection uncapturing

Prevent stack overflow during uncapturing of star projection
for parameter with recursive upper bound.
Uncapture star projections for flexible type parameters with
respect to flexible upper bound.

^KT-35210 Fixed
This commit is contained in:
Pavel Kirpichenkov
2019-12-16 20:51:29 +03:00
parent 86dc0925b1
commit ebb9f09656
15 changed files with 317 additions and 9 deletions
@@ -1898,6 +1898,11 @@ public class FirOldFrontendDiagnosticsTestWithStdlibGenerated extends AbstractFi
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/kt29307.kt"); runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/kt29307.kt");
} }
@TestMetadata("kt35210.kt")
public void testKt35210() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/kt35210.kt");
}
@TestMetadata("noInferAndLowPriority.kt") @TestMetadata("noInferAndLowPriority.kt")
public void testNoInferAndLowPriority() throws Exception { public void testNoInferAndLowPriority() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/noInferAndLowPriority.kt"); runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/noInferAndLowPriority.kt");
@@ -1913,6 +1918,16 @@ public class FirOldFrontendDiagnosticsTestWithStdlibGenerated extends AbstractFi
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/notNullAnnotation.kt"); runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/notNullAnnotation.kt");
} }
@TestMetadata("onlyInputTypeAndJava.kt")
public void testOnlyInputTypeAndJava() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypeAndJava.kt");
}
@TestMetadata("onlyInputTypeRecursiveBoundAndProjections.kt")
public void testOnlyInputTypeRecursiveBoundAndProjections() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypeRecursiveBoundAndProjections.kt");
}
@TestMetadata("onlyInputTypes.kt") @TestMetadata("onlyInputTypes.kt")
public void testOnlyInputTypes() throws Exception { public void testOnlyInputTypes() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypes.kt"); runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypes.kt");
@@ -1938,6 +1953,16 @@ public class FirOldFrontendDiagnosticsTestWithStdlibGenerated extends AbstractFi
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesCaptured.kt"); runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesCaptured.kt");
} }
@TestMetadata("onlyInputTypesCommonConstraintSystem.kt")
public void testOnlyInputTypesCommonConstraintSystem() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesCommonConstraintSystem.kt");
}
@TestMetadata("onlyInputTypesUpperBound.kt")
public void testOnlyInputTypesUpperBound() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesUpperBound.kt");
}
@TestMetadata("onlyInputTypesWithVarargs.kt") @TestMetadata("onlyInputTypesWithVarargs.kt")
public void testOnlyInputTypesWithVarargs() throws Exception { public void testOnlyInputTypesWithVarargs() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesWithVarargs.kt"); runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesWithVarargs.kt");
@@ -0,0 +1,12 @@
// !LANGUAGE: +NewInference
// !DIAGNOSTICS: -UNUSED_PARAMETER
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
annotation class Anno
fun test(a: List<Class<Anno>>) {
strictSelect(a, emptyList<Anno>().map { it.annotationClass.java })
}
fun <@kotlin.internal.OnlyInputTypes S> strictSelect(arg1: S, arg2: S): S = TODO()
@@ -0,0 +1,18 @@
// !LANGUAGE: +NewInference
// !DIAGNOSTICS: -UNUSED_PARAMETER
// FILE: TestBase.java
public class TestBase<T> { }
// FILE: Test.java
public class Test<K> extends TestBase<K> { }
// FILE: main.kt
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
fun <@kotlin.internal.OnlyInputTypes K> TestBase<out K>.foo(key: K) = null
fun foo(result: Test<*>) {
result.foo("sd") // Type inference failed (NI), OK in OI
}
@@ -0,0 +1,18 @@
// !LANGUAGE: +NewInference
// !DIAGNOSTICS: -UNUSED_PARAMETER
// FILE: TestBase.java
public class TestBase<T> { }
// FILE: Test.java
public class Test<K> extends TestBase<K> { }
// FILE: main.kt
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
fun <@kotlin.internal.OnlyInputTypes K> TestBase<out K>.foo(key: K) = null
fun foo(result: Test<*>) {
result.foo("sd") // Type inference failed (NI), OK in OI
}
@@ -0,0 +1,18 @@
package
public fun foo(/*0*/ result: Test<*>): kotlin.Unit
@kotlin.Suppress(names = {"INVISIBLE_MEMBER", "INVISIBLE_REFERENCE"}) public fun </*0*/ @kotlin.internal.OnlyInputTypes K> TestBase<out K>.foo(/*0*/ key: K): kotlin.Nothing?
public open class Test</*0*/ K : kotlin.Any!> : TestBase<K!> {
public constructor Test</*0*/ K : kotlin.Any!>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class TestBase</*0*/ T : kotlin.Any!> {
public constructor TestBase</*0*/ T : kotlin.Any!>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,24 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
interface IFace<K, out V>
fun <@kotlin.internal.OnlyInputTypes K, V> IFace<out K, V>.get(key: K): V? = TODO()
fun <@kotlin.internal.OnlyInputTypes I> id(arg: I): I = arg
interface InvBase<B>
class DerivedInv : InvBase<DerivedInv>
class InvRecursive<E : InvBase<E>>
fun test1(argument: InvRecursive<*>, receiver: IFace<InvRecursive<DerivedInv>, Any>) {
receiver.get(argument)
}
fun test2(arg: InvRecursive<out DerivedInv>) {
id(arg)
}
fun test3(arg: InvRecursive<in DerivedInv>) {
id(arg)
}
@@ -0,0 +1,24 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
interface IFace<K, out V>
fun <@kotlin.internal.OnlyInputTypes K, V> IFace<out K, V>.get(key: K): V? = TODO()
fun <@kotlin.internal.OnlyInputTypes I> id(arg: I): I = arg
interface InvBase<B>
class DerivedInv : InvBase<DerivedInv>
class InvRecursive<E : InvBase<E>>
fun test1(argument: InvRecursive<*>, receiver: IFace<InvRecursive<DerivedInv>, Any>) {
receiver.get(argument)
}
fun test2(arg: InvRecursive<out DerivedInv>) {
id(arg)
}
fun test3(arg: InvRecursive<in DerivedInv>) {
id(arg)
}
@@ -0,0 +1,33 @@
package
public fun </*0*/ @kotlin.internal.OnlyInputTypes I> id(/*0*/ arg: I): I
public fun test1(/*0*/ argument: InvRecursive<*>, /*1*/ receiver: IFace<InvRecursive<DerivedInv>, kotlin.Any>): kotlin.Unit
public fun test2(/*0*/ arg: InvRecursive<out DerivedInv>): kotlin.Unit
public fun test3(/*0*/ arg: InvRecursive<in DerivedInv>): kotlin.Unit
public fun </*0*/ @kotlin.internal.OnlyInputTypes K, /*1*/ V> IFace<out K, V>.get(/*0*/ key: K): V?
public final class DerivedInv : InvBase<DerivedInv> {
public constructor DerivedInv()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface IFace</*0*/ K, /*1*/ out V> {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface InvBase</*0*/ B> {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class InvRecursive</*0*/ E : InvBase<E>> {
public constructor InvRecursive</*0*/ E : InvBase<E>>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,54 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
// !WITH_NEW_INFERENCE
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
import kotlin.internal.OnlyInputTypes
interface Bound
class First : Bound
class Second : Bound
class Inv<I >(val v: I)
class InvB<I : Bound>(val v: I)
class In<in C>(v: C)
class InB<in C : Bound>(v: C)
class Out<out O>(val v: O)
class OutB<out O : Bound>(val v: O)
fun <@OnlyInputTypes M> strictId(arg: M): M = arg
fun <@OnlyInputTypes S> strictSelect(arg1: S, arg2: S): S = arg1
fun testOK(first: First, bound: Bound, second: Second) {
strictId(Inv(15))
strictId(Inv("foo"))
strictId(Inv(first))
strictId(InvB(first))
strictId(In(first))
strictId(InB(first))
strictId(Out(first))
strictId(OutB(first))
strictId(Inv(Inv(Inv(first))))
strictSelect(Inv(first), Inv(first))
strictSelect(InvB(first), InvB(first))
strictSelect(Out(first), Out(bound))
strictSelect(OutB(first), OutB(bound))
strictSelect(In(first), In(bound))
strictSelect(InB(first), InB(bound))
strictSelect(InB(first), InB(second)) // different behaviour in contravariant position
val out: Out<Bound> = strictSelect(Out(first), Out(second))
val outb: OutB<Bound> = strictSelect(OutB(first), OutB(second))
strictSelect<Out<Bound>>(Out(first), Out(second))
strictSelect<OutB<Bound>>(OutB(first), OutB(second))
}
fun testFail(first: First, bound: Bound, second: Second) {
strictSelect(InvB(first), InvB(bound))
strictSelect(Inv(first), Inv(bound))
strictSelect(Out(first), Out(second))
strictSelect(In(first), In(second))
strictSelect(Out(Inv(first)), Out(Inv(second)))
strictSelect(In(Inv(first)), In(Inv(second)))
}
@@ -0,0 +1,12 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
// !WITH_NEW_INFERENCE
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
class Inv<T>
class Out<out T>
fun <T> foo(i: Inv<in T>, o: Out<T>) {
bar(i, o)
}
fun <@kotlin.internal.OnlyInputTypes K> bar(r: Inv<out K>, o: Out<K>): K = TODO()
@@ -0,0 +1,12 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
// !WITH_NEW_INFERENCE
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
class Inv<T>
class Out<out T>
fun <T> foo(i: Inv<in T>, o: Out<T>) {
<!NI;TYPE_INFERENCE_ONLY_INPUT_TYPES!>bar<!>(i, o)
}
fun <@kotlin.internal.OnlyInputTypes K> bar(r: Inv<out K>, o: Out<K>): K = TODO()
@@ -0,0 +1,18 @@
package
public fun </*0*/ @kotlin.internal.OnlyInputTypes K> bar(/*0*/ r: Inv<out K>, /*1*/ o: Out<K>): K
public fun </*0*/ T> foo(/*0*/ i: Inv<in T>, /*1*/ o: Out<T>): kotlin.Unit
public final class Inv</*0*/ T> {
public constructor Inv</*0*/ T>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Out</*0*/ out T> {
public constructor Out</*0*/ out T>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -2818,6 +2818,16 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/notNullAnnotation.kt"); runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/notNullAnnotation.kt");
} }
@TestMetadata("onlyInputTypeAndJava.kt")
public void testOnlyInputTypeAndJava() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypeAndJava.kt");
}
@TestMetadata("onlyInputTypeRecursiveBoundAndProjections.kt")
public void testOnlyInputTypeRecursiveBoundAndProjections() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypeRecursiveBoundAndProjections.kt");
}
@TestMetadata("onlyInputTypes.kt") @TestMetadata("onlyInputTypes.kt")
public void testOnlyInputTypes() throws Exception { public void testOnlyInputTypes() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypes.kt"); runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypes.kt");
@@ -2848,6 +2858,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesCommonConstraintSystem.kt"); runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesCommonConstraintSystem.kt");
} }
@TestMetadata("onlyInputTypesUpperBound.kt")
public void testOnlyInputTypesUpperBound() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesUpperBound.kt");
}
@TestMetadata("onlyInputTypesWithVarargs.kt") @TestMetadata("onlyInputTypesWithVarargs.kt")
public void testOnlyInputTypesWithVarargs() throws Exception { public void testOnlyInputTypesWithVarargs() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesWithVarargs.kt"); runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesWithVarargs.kt");
@@ -2818,6 +2818,16 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/notNullAnnotation.kt"); runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/notNullAnnotation.kt");
} }
@TestMetadata("onlyInputTypeAndJava.kt")
public void testOnlyInputTypeAndJava() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypeAndJava.kt");
}
@TestMetadata("onlyInputTypeRecursiveBoundAndProjections.kt")
public void testOnlyInputTypeRecursiveBoundAndProjections() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypeRecursiveBoundAndProjections.kt");
}
@TestMetadata("onlyInputTypes.kt") @TestMetadata("onlyInputTypes.kt")
public void testOnlyInputTypes() throws Exception { public void testOnlyInputTypes() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypes.kt"); runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypes.kt");
@@ -2848,6 +2858,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesCommonConstraintSystem.kt"); runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesCommonConstraintSystem.kt");
} }
@TestMetadata("onlyInputTypesUpperBound.kt")
public void testOnlyInputTypesUpperBound() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesUpperBound.kt");
}
@TestMetadata("onlyInputTypesWithVarargs.kt") @TestMetadata("onlyInputTypesWithVarargs.kt")
public void testOnlyInputTypesWithVarargs() throws Exception { public void testOnlyInputTypesWithVarargs() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesWithVarargs.kt"); runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/onlyInputTypesWithVarargs.kt");
@@ -257,11 +257,7 @@ fun KotlinType.unCapture(): KotlinType = unwrap().unCapture()
fun UnwrappedType.unCapture(): UnwrappedType = when (this) { fun UnwrappedType.unCapture(): UnwrappedType = when (this) {
is AbbreviatedType -> unCapture() is AbbreviatedType -> unCapture()
is SimpleType -> unCapture() is SimpleType -> unCapture()
is FlexibleType -> is FlexibleType -> unCapture()
FlexibleTypeImpl(
lowerBound.unCapture() as? SimpleType ?: lowerBound,
upperBound.unCapture() as? SimpleType ?: upperBound
)
} }
fun SimpleType.unCapture(): UnwrappedType { fun SimpleType.unCapture(): UnwrappedType {
@@ -274,10 +270,8 @@ fun SimpleType.unCapture(): UnwrappedType {
} }
fun unCaptureProjection(projection: TypeProjection): TypeProjection { fun unCaptureProjection(projection: TypeProjection): TypeProjection {
val unCapturedProjection = projection.type.constructor.safeAs<NewCapturedTypeConstructor>()?.let { val unCapturedProjection = projection.type.constructor.safeAs<NewCapturedTypeConstructor>()?.projection ?: projection
it.projection if (unCapturedProjection.isStarProjection || unCapturedProjection.type is ErrorType) return unCapturedProjection
} ?: projection
if (unCapturedProjection.type is ErrorType) return unCapturedProjection
val newArguments = unCapturedProjection.type.arguments.map(::unCaptureProjection) val newArguments = unCapturedProjection.type.arguments.map(::unCaptureProjection)
return TypeProjectionImpl( return TypeProjectionImpl(
@@ -291,6 +285,22 @@ fun AbbreviatedType.unCapture(): SimpleType {
return AbbreviatedType(newType as? SimpleType ?: expandedType, abbreviation) return AbbreviatedType(newType as? SimpleType ?: expandedType, abbreviation)
} }
fun FlexibleType.unCapture(): FlexibleType {
val unCapturedLowerBound = when (val unCaptured = lowerBound.unCapture()) {
is SimpleType -> unCaptured
is FlexibleType -> unCaptured.lowerBound
else -> lowerBound
}
val unCapturedUpperBound = when (val unCaptured = upperBound.unCapture()) {
is SimpleType -> unCaptured
is FlexibleType -> unCaptured.upperBound
else -> upperBound
}
return FlexibleTypeImpl(unCapturedLowerBound, unCapturedUpperBound)
}
private fun NewCapturedType.unCaptureTopLevelType(): UnwrappedType { private fun NewCapturedType.unCaptureTopLevelType(): UnwrappedType {
if (lowerType != null) return lowerType if (lowerType != null) return lowerType