Fix supertypes calculation for types with projections
Use captured types as replacement for non top-level entries #KT-7296 Fixed
This commit is contained in:
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
// !CHECK_TYPE
|
||||
|
||||
public abstract class A<E> {
|
||||
fun bar(): String = ""
|
||||
}
|
||||
|
||||
public class B<F> : A<B<F>>()
|
||||
|
||||
fun test(b: B<*>) {
|
||||
// Here `bar` could have dispatch receiver parameter type 'A<B<Captured(*)>>', but it wouldn't work as
|
||||
// since 'b' has type 'A<out B<*>>', so we should approximate dispatch receiver PARAMETER type to make it accept original receiver
|
||||
b.bar()
|
||||
b.bar() checkType { _<String>() }
|
||||
}
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
package
|
||||
|
||||
public fun test(/*0*/ b: B<*>): kotlin.Unit
|
||||
|
||||
public abstract class A</*0*/ E> {
|
||||
public constructor A</*0*/ E>()
|
||||
public final fun bar(): kotlin.String
|
||||
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 B</*0*/ F> : A<B<F>> {
|
||||
public constructor B</*0*/ F>()
|
||||
public final override /*1*/ /*fake_override*/ fun bar(): kotlin.String
|
||||
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
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
// !CHECK_TYPE
|
||||
|
||||
// FILE: Clazz.java
|
||||
public class Clazz<Psi> {
|
||||
public java.util.Collection<Psi> foo() { return null; }
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
|
||||
public fun <T, C : MutableCollection<in T>> Iterable<T>.filterTo(destination: C, predicate: (T) -> Boolean) {}
|
||||
|
||||
fun test(clazz: Clazz<out Any>) {
|
||||
val result = java.util.ArrayList<Any>()
|
||||
clazz.foo().filterTo(result) { x -> true }
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package
|
||||
|
||||
public fun test(/*0*/ clazz: Clazz<out kotlin.Any>): kotlin.Unit
|
||||
public fun </*0*/ T, /*1*/ C : kotlin.MutableCollection<in T>> kotlin.Iterable<T>.filterTo(/*0*/ destination: C, /*1*/ predicate: (T) -> kotlin.Boolean): kotlin.Unit
|
||||
|
||||
public open class Clazz</*0*/ Psi : kotlin.Any!> {
|
||||
public constructor Clazz</*0*/ Psi : kotlin.Any!>()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open fun foo(): kotlin.(Mutable)Collection<Psi!>!
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+6
-2
@@ -4,7 +4,11 @@ interface A<T>
|
||||
interface B<T> : A<A<T>>
|
||||
|
||||
fun foo(x : B<*>) {
|
||||
bar(x) // this should not be valid
|
||||
bar1(<!TYPE_MISMATCH!>x<!>) // this should not be valid
|
||||
bar2(x)
|
||||
bar3(x)
|
||||
}
|
||||
|
||||
fun bar(x : A<A<*>>) { }
|
||||
fun bar1(x : A<A<*>>) { }
|
||||
fun bar2(x : A<out A<*>>) { }
|
||||
fun bar3(x : A<*>) { }
|
||||
|
||||
+3
-1
@@ -1,6 +1,8 @@
|
||||
package
|
||||
|
||||
public fun bar(/*0*/ x: A<A<*>>): kotlin.Unit
|
||||
public fun bar1(/*0*/ x: A<A<*>>): kotlin.Unit
|
||||
public fun bar2(/*0*/ x: A<out A<*>>): kotlin.Unit
|
||||
public fun bar3(/*0*/ x: A<*>): kotlin.Unit
|
||||
public fun foo(/*0*/ x: B<*>): kotlin.Unit
|
||||
|
||||
public interface A</*0*/ T> {
|
||||
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
// See KT-7296
|
||||
interface Out<out F>
|
||||
interface B<T> : Out<Out<T>>
|
||||
|
||||
fun foo(x : B<*>) {
|
||||
bar1(x)
|
||||
bar2(x)
|
||||
}
|
||||
|
||||
fun bar1(x : Out<Out<*>>) { }
|
||||
fun bar2(x : Out<*>) { }
|
||||
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
package
|
||||
|
||||
public fun bar1(/*0*/ x: Out<Out<*>>): kotlin.Unit
|
||||
public fun bar2(/*0*/ x: Out<*>): kotlin.Unit
|
||||
public fun foo(/*0*/ x: B<*>): kotlin.Unit
|
||||
|
||||
public interface B</*0*/ T> : Out<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
|
||||
}
|
||||
|
||||
public interface Out</*0*/ out F> {
|
||||
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
|
||||
}
|
||||
@@ -7130,12 +7130,24 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/generics/projectionsScope"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("approximateDispatchReceiver.kt")
|
||||
public void testApproximateDispatchReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/approximateDispatchReceiver.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("extensionResultSubstitution.kt")
|
||||
public void testExtensionResultSubstitution() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/extensionResultSubstitution.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("flexibleProjectedScope.kt")
|
||||
public void testFlexibleProjectedScope() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/flexibleProjectedScope.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt7296.kt")
|
||||
public void testKt7296() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/kt7296.kt");
|
||||
@@ -7172,6 +7184,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("recursiveUpperBoundStarOut.kt")
|
||||
public void testRecursiveUpperBoundStarOut() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/recursiveUpperBoundStarOut.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("starNullability.kt")
|
||||
public void testStarNullability() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/starNullability.kt");
|
||||
|
||||
@@ -62,6 +62,9 @@ public abstract class TypeConstructorSubstitution : TypeSubstitution() {
|
||||
override fun isEmpty() = map.isEmpty()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
public fun create(kotlinType: KotlinType) = create(kotlinType.constructor, kotlinType.arguments)
|
||||
|
||||
@JvmStatic
|
||||
public fun create(typeConstructor: TypeConstructor, arguments: List<TypeProjection>): TypeSubstitution {
|
||||
val parameters = typeConstructor.parameters
|
||||
|
||||
@@ -16,11 +16,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.types.checker
|
||||
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.wrapWithCapturingSubstitution
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.TypeConstructorSubstitution
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.checker.TypeCheckingProcedureCallbacks
|
||||
import org.jetbrains.kotlin.types.typesApproximation.approximateCapturedTypes
|
||||
import java.util.*
|
||||
|
||||
private class SubtypePathNode(val type: KotlinType, val previous: SubtypePathNode?)
|
||||
@@ -46,8 +47,20 @@ public fun findCorrespondingSupertype(
|
||||
var currentPathNode = lastPathNode.previous
|
||||
|
||||
while (currentPathNode != null) {
|
||||
substituted = TypeSubstitutor.create(currentPathNode.type).safeSubstitute(substituted, Variance.INVARIANT)
|
||||
isAnyMarkedNullable = isAnyMarkedNullable || currentPathNode.type.isMarkedNullable
|
||||
val currentType = currentPathNode.type
|
||||
if (currentType.arguments.any { it.projectionKind != Variance.INVARIANT }) {
|
||||
substituted = TypeConstructorSubstitution.create(currentType)
|
||||
.wrapWithCapturingSubstitution().buildSubstitutor()
|
||||
.safeSubstitute(substituted, Variance.INVARIANT)
|
||||
.approximate()
|
||||
}
|
||||
else {
|
||||
substituted = TypeConstructorSubstitution.create(currentType)
|
||||
.buildSubstitutor()
|
||||
.safeSubstitute(substituted, Variance.INVARIANT)
|
||||
}
|
||||
|
||||
isAnyMarkedNullable = isAnyMarkedNullable || currentType.isMarkedNullable
|
||||
|
||||
currentPathNode = currentPathNode.previous
|
||||
}
|
||||
@@ -62,3 +75,5 @@ public fun findCorrespondingSupertype(
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun KotlinType.approximate() = approximateCapturedTypes(this).upper
|
||||
|
||||
Reference in New Issue
Block a user