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>>
|
interface B<T> : A<A<T>>
|
||||||
|
|
||||||
fun foo(x : B<*>) {
|
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
|
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 fun foo(/*0*/ x: B<*>): kotlin.Unit
|
||||||
|
|
||||||
public interface A</*0*/ T> {
|
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);
|
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")
|
@TestMetadata("extensionResultSubstitution.kt")
|
||||||
public void testExtensionResultSubstitution() throws Exception {
|
public void testExtensionResultSubstitution() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/extensionResultSubstitution.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/extensionResultSubstitution.kt");
|
||||||
doTest(fileName);
|
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")
|
@TestMetadata("kt7296.kt")
|
||||||
public void testKt7296() throws Exception {
|
public void testKt7296() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/kt7296.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/kt7296.kt");
|
||||||
@@ -7172,6 +7184,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("starNullability.kt")
|
||||||
public void testStarNullability() throws Exception {
|
public void testStarNullability() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/starNullability.kt");
|
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()
|
override fun isEmpty() = map.isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
public fun create(kotlinType: KotlinType) = create(kotlinType.constructor, kotlinType.arguments)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
public fun create(typeConstructor: TypeConstructor, arguments: List<TypeProjection>): TypeSubstitution {
|
public fun create(typeConstructor: TypeConstructor, arguments: List<TypeProjection>): TypeSubstitution {
|
||||||
val parameters = typeConstructor.parameters
|
val parameters = typeConstructor.parameters
|
||||||
|
|||||||
@@ -16,11 +16,12 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.types.checker
|
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.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
import org.jetbrains.kotlin.types.TypeConstructorSubstitution
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
import org.jetbrains.kotlin.types.checker.TypeCheckingProcedureCallbacks
|
import org.jetbrains.kotlin.types.typesApproximation.approximateCapturedTypes
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
private class SubtypePathNode(val type: KotlinType, val previous: SubtypePathNode?)
|
private class SubtypePathNode(val type: KotlinType, val previous: SubtypePathNode?)
|
||||||
@@ -46,8 +47,20 @@ public fun findCorrespondingSupertype(
|
|||||||
var currentPathNode = lastPathNode.previous
|
var currentPathNode = lastPathNode.previous
|
||||||
|
|
||||||
while (currentPathNode != null) {
|
while (currentPathNode != null) {
|
||||||
substituted = TypeSubstitutor.create(currentPathNode.type).safeSubstitute(substituted, Variance.INVARIANT)
|
val currentType = currentPathNode.type
|
||||||
isAnyMarkedNullable = isAnyMarkedNullable || currentPathNode.type.isMarkedNullable
|
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
|
currentPathNode = currentPathNode.previous
|
||||||
}
|
}
|
||||||
@@ -62,3 +75,5 @@ public fun findCorrespondingSupertype(
|
|||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun KotlinType.approximate() = approximateCapturedTypes(this).upper
|
||||||
|
|||||||
Reference in New Issue
Block a user