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:
Denis Zharkov
2015-12-23 12:59:42 +03:00
parent 397d2ca312
commit 722a152a74
11 changed files with 139 additions and 7 deletions
@@ -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>() }
}
@@ -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
}
@@ -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 }
}
@@ -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
}
@@ -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<*>) { }
@@ -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> {
@@ -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<*>) { }
@@ -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