From e2c02f825f0bc812e48fd692ca657c30e87b47a4 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Tue, 22 Dec 2015 14:02:55 +0300 Subject: [PATCH] Refine member scope for types with projections Instead of erasing descriptors with conflicting substitution, use invariant CapturedType() as replacement for type parameter within default member scope. After substitution leave such types 'as is' everywhere except return types, use common approximation for them. #KT-9294 In Progress #KT-5411 Fixed #KT-8647 Fixed #KT-9462 Fixed #KT-9893 Fixed #KT-7581 Fixed #KT-7296 In Progress --- .../kt7383_starProjectedFunction.kt | 2 +- .../diagnostics/tests/generics/Projections.kt | 8 +- .../generics/innerClasses/simpleOutUseSite.kt | 7 +- .../tests/generics/projectionsScope/MLOut.kt | 18 ++++ .../tests/generics/projectionsScope/MLOut.txt | 11 +++ .../tests/generics/projectionsScope/addAll.kt | 27 ++++++ .../generics/projectionsScope/addAll.txt | 32 +++++++ .../extensionResultSubstitution.kt | 13 +++ .../extensionResultSubstitution.txt | 18 ++++ .../tests/generics/projectionsScope/kt7296.kt | 14 +++ .../generics/projectionsScope/kt7296.txt | 11 +++ .../tests/generics/projectionsScope/kt8647.kt | 8 ++ .../generics/projectionsScope/kt8647.txt | 16 ++++ .../projectionsScope/lambdaArgument.kt | 16 ++++ .../projectionsScope/lambdaArgument.txt | 11 +++ .../recursiveUpperBoundStar.kt | 10 +++ .../recursiveUpperBoundStar.txt | 16 ++++ .../projectionsScope/starNullability.kt | 16 ++++ .../projectionsScope/starNullability.txt | 18 ++++ .../starNullabilityRecursive.kt | 8 ++ .../starNullabilityRecursive.txt | 10 +++ .../generics/projectionsScope/superClass.kt | 12 +++ .../generics/projectionsScope/superClass.txt | 11 +++ .../projectionsScope/typeParameterBounds.kt | 43 +++++++++ .../projectionsScope/typeParameterBounds.txt | 34 ++++++++ .../projectionsScope/unsafeVarianceStar.kt | 9 ++ .../projectionsScope/unsafeVarianceStar.txt | 10 +++ .../capturedTypes/memberScopeOfCaptured.kt | 1 + .../tests/j+k/arrayOfStarParametrized.kt | 14 +++ .../tests/j+k/arrayOfStarParametrized.txt | 12 +++ .../testsWithStdLib/addAllProjection.kt | 13 +++ .../testsWithStdLib/addAllProjection.txt | 3 + compiler/testData/resolve/Projections.resolve | 14 +-- .../checkers/DiagnosticsTestGenerated.java | 87 +++++++++++++++++++ .../DiagnosticsTestWithStdLibGenerated.java | 6 ++ .../CapturedTypeApproximationTest.kt | 33 +++---- .../AbstractReceiverParameterDescriptor.java | 15 +++- .../inference/CapturedTypeConstructor.kt | 31 +++++++ .../resolve/scopes/SubstitutingScope.kt | 31 ++++--- .../kotlin/types/CapturedTypeApproximation.kt | 13 ++- .../kotlin/types/DescriptorSubstitutor.java | 2 +- .../DisjointKeysUnionTypeSubstitution.kt | 1 + .../kotlin/types/TypeSubstitution.kt | 13 ++- .../kotlin/types/TypeSubstitutor.java | 5 +- .../basic/extensionFunForArray.kt | 2 +- .../basic/extensionFunForArray.kt.after | 2 +- .../candidateTypes/nonNullableTypes.kt | 2 +- .../candidateTypes/nonNullableTypes.kt.after | 2 +- .../parameters/extractThis/qualifiedThis.kt | 2 +- .../extractThis/qualifiedThis.kt.after | 2 +- 50 files changed, 655 insertions(+), 60 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/MLOut.kt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/MLOut.txt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/addAll.kt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/addAll.txt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/extensionResultSubstitution.kt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/extensionResultSubstitution.txt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/kt7296.kt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/kt7296.txt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/kt8647.kt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/kt8647.txt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/lambdaArgument.kt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/lambdaArgument.txt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/recursiveUpperBoundStar.kt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/recursiveUpperBoundStar.txt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/starNullability.kt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/starNullability.txt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/starNullabilityRecursive.kt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/starNullabilityRecursive.txt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/superClass.kt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/superClass.txt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/typeParameterBounds.kt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/typeParameterBounds.txt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceStar.kt create mode 100644 compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceStar.txt create mode 100644 compiler/testData/diagnostics/tests/j+k/arrayOfStarParametrized.kt create mode 100644 compiler/testData/diagnostics/tests/j+k/arrayOfStarParametrized.txt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/addAllProjection.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/addAllProjection.txt diff --git a/compiler/testData/diagnostics/tests/functionLiterals/kt7383_starProjectedFunction.kt b/compiler/testData/diagnostics/tests/functionLiterals/kt7383_starProjectedFunction.kt index 10691a9c534..54e02ed4d81 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/kt7383_starProjectedFunction.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/kt7383_starProjectedFunction.kt @@ -2,5 +2,5 @@ fun foo() { val f : Function1<*, *> = { x -> x.toString() } - f(1) + f(1) } diff --git a/compiler/testData/diagnostics/tests/generics/Projections.kt b/compiler/testData/diagnostics/tests/generics/Projections.kt index d7dd8d9253d..7ee0af5c475 100644 --- a/compiler/testData/diagnostics/tests/generics/Projections.kt +++ b/compiler/testData/diagnostics/tests/generics/Projections.kt @@ -36,13 +36,13 @@ fun testInOut() { Inv().f(1) (null as Inv).f(1) - (null as Inv).f(1) // !! - (null as Inv<*>).f(1) // !! + (null as Inv).f(1) // !! + (null as Inv<*>).f(1) // !! Inv().inf(1) (null as Inv).inf(1) - (null as Inv).inf(1) // !! - (null as Inv<*>).inf(1) // !! + (null as Inv).inf(1) // !! + (null as Inv<*>).inf(1) // !! Inv().outf() checkSubtype((null as Inv).outf()) // Type mismatch diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/simpleOutUseSite.kt b/compiler/testData/diagnostics/tests/generics/innerClasses/simpleOutUseSite.kt index cd486f63f12..76e834d15c0 100644 --- a/compiler/testData/diagnostics/tests/generics/innerClasses/simpleOutUseSite.kt +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/simpleOutUseSite.kt @@ -28,10 +28,9 @@ fun main() { checkSubtype.Inner>(outer.bar()) checkSubtype.Inner>(outer.Inner()) - // Should not actually work as in Java (captured constructor type mismatch) - outer.set(outer.bar()) - outer.set(outer.Inner()) + outer.set(.Inner)!>outer.bar()) + outer.set(.Inner)!>outer.Inner()) val x: Outer.Inner = factoryString() - outer.set(x) + outer.set(.Inner)!>x) } diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/MLOut.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/MLOut.kt new file mode 100644 index 00000000000..8f573bce36f --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/MLOut.kt @@ -0,0 +1,18 @@ +// !CHECK_TYPE + +// FILE: A.java +public class A { + public java.util.List foo() {} +} + +// FILE: main.kt + +fun foo2(x: A, y: MutableList) { + x.foo().isEmpty() + x.foo().get(0) checkType { _() } + x.foo().iterator() checkType { _>() } + + y.isEmpty() + y.get(0) checkType { _() } + y.iterator() checkType { _>() } +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/MLOut.txt b/compiler/testData/diagnostics/tests/generics/projectionsScope/MLOut.txt new file mode 100644 index 00000000000..d27266c8fd0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/MLOut.txt @@ -0,0 +1,11 @@ +package + +public fun foo2(/*0*/ x: A, /*1*/ y: kotlin.MutableList): kotlin.Unit + +public open class A { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun foo(): (kotlin.MutableList..kotlin.List?) + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/addAll.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/addAll.kt new file mode 100644 index 00000000000..e6e4396601b --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/addAll.kt @@ -0,0 +1,27 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +interface C +interface MC : C { + fun addAll(x: C): Boolean + fun addAllMC(x: MC): Boolean +} + +interface Open +class Derived : Open + +fun mc(): MC = null!! +fun c(): C = null!! + +fun foo(x: MC) { + x.addAll(; MC)!>x) + x.addAllMC(; MC)!>x) + + x.addAll(; MC)!>mc()) + x.addAllMC(; MC)!>mc()) + + x.addAll(; MC)!>mc()) + x.addAllMC(; MC)!>mc()) + + x.addAll(c()) + x.addAll(c()) +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/addAll.txt b/compiler/testData/diagnostics/tests/generics/projectionsScope/addAll.txt new file mode 100644 index 00000000000..ae151570fd4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/addAll.txt @@ -0,0 +1,32 @@ +package + +public fun c(): C +public fun foo(/*0*/ x: MC): kotlin.Unit +public fun mc(): MC + +public interface C { + 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 Derived : Open { + public constructor Derived() + 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 MC : C { + public abstract fun addAll(/*0*/ x: C): kotlin.Boolean + public abstract fun addAllMC(/*0*/ x: MC): kotlin.Boolean + 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 Open { + 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 +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/extensionResultSubstitution.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/extensionResultSubstitution.kt new file mode 100644 index 00000000000..a200e8f6eee --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/extensionResultSubstitution.kt @@ -0,0 +1,13 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +class A { + fun foo() = 1 +} + +interface B + +public fun E.bar() : A = null!! + +fun baz(x: B) { + x.bar().foo() +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/extensionResultSubstitution.txt b/compiler/testData/diagnostics/tests/generics/projectionsScope/extensionResultSubstitution.txt new file mode 100644 index 00000000000..2203ce4ed67 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/extensionResultSubstitution.txt @@ -0,0 +1,18 @@ +package + +public fun baz(/*0*/ x: B): kotlin.Unit +public fun E.bar(): A + +public final class A { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun foo(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface 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 +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/kt7296.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/kt7296.kt new file mode 100644 index 00000000000..4f8daf124d9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/kt7296.kt @@ -0,0 +1,14 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE +// !CHECK_TYPE +import java.util.ArrayList + +class ListOfLists(public val x : ArrayList>) + +fun main(args : Array) { + val a : ArrayList> = ArrayList() + val b : ListOfLists = ListOfLists(a) + val c : ListOfLists<*> = b + val d : ArrayList> = c.x + + c.x checkType { _>>() } +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/kt7296.txt b/compiler/testData/diagnostics/tests/generics/projectionsScope/kt7296.txt new file mode 100644 index 00000000000..9e283e3e56e --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/kt7296.txt @@ -0,0 +1,11 @@ +package + +public fun main(/*0*/ args: kotlin.Array): kotlin.Unit + +public final class ListOfLists { + public constructor ListOfLists(/*0*/ x: java.util.ArrayList>) + public final val x: java.util.ArrayList> + 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 +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/kt8647.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/kt8647.kt new file mode 100644 index 00000000000..0873de21fd3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/kt8647.kt @@ -0,0 +1,8 @@ +interface Subscriber + +interface Observable { + fun subscribe(s: Subscriber) +} + +fun foo(o: Observable, y: Subscriber) = o.subscribe(y) // type safe + diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/kt8647.txt b/compiler/testData/diagnostics/tests/generics/projectionsScope/kt8647.txt new file mode 100644 index 00000000000..5655ea25147 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/kt8647.txt @@ -0,0 +1,16 @@ +package + +public fun foo(/*0*/ o: Observable, /*1*/ y: Subscriber): kotlin.Unit + +public interface Observable { + 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 abstract fun subscribe(/*0*/ s: Subscriber): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Subscriber { + 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 +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/lambdaArgument.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/lambdaArgument.kt new file mode 100644 index 00000000000..8a6cf24aa9f --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/lambdaArgument.kt @@ -0,0 +1,16 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !CHECK_TYPE + +class A { + fun foo(f: (T) -> Unit) {} +} + +fun test(a: A, b: A) { + a.foo { + it checkType { _() } + } + + b.foo { + it checkType { _() } + } +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/lambdaArgument.txt b/compiler/testData/diagnostics/tests/generics/projectionsScope/lambdaArgument.txt new file mode 100644 index 00000000000..c4a9a5bb2e4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/lambdaArgument.txt @@ -0,0 +1,11 @@ +package + +public fun test(/*0*/ a: A, /*1*/ b: A): kotlin.Unit + +public final class A { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun foo(/*0*/ f: (T) -> kotlin.Unit): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/recursiveUpperBoundStar.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/recursiveUpperBoundStar.kt new file mode 100644 index 00000000000..2fbe845857a --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/recursiveUpperBoundStar.kt @@ -0,0 +1,10 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// See KT-7296 +interface A +interface B : A> + +fun foo(x : B<*>) { + bar(x) // this should not be valid +} + +fun bar(x : A>) { } diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/recursiveUpperBoundStar.txt b/compiler/testData/diagnostics/tests/generics/projectionsScope/recursiveUpperBoundStar.txt new file mode 100644 index 00000000000..cd0f39dae8b --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/recursiveUpperBoundStar.txt @@ -0,0 +1,16 @@ +package + +public fun bar(/*0*/ x: A>): kotlin.Unit +public fun foo(/*0*/ x: B<*>): kotlin.Unit + +public interface A { + 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 B : A> { + 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 +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/starNullability.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/starNullability.kt new file mode 100644 index 00000000000..d2fa6b9320e --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/starNullability.kt @@ -0,0 +1,16 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !CHECK_TYPE +// See KT-9893 +open class A + +public interface I { + public fun foo(): T? +} + +fun acceptA(a: A) { +} + +fun main(i: I<*>) { + i.foo() checkType { _() } + acceptA(i.foo()) // i.foo() should be nullable but isn't +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/starNullability.txt b/compiler/testData/diagnostics/tests/generics/projectionsScope/starNullability.txt new file mode 100644 index 00000000000..c7bde7be8d7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/starNullability.txt @@ -0,0 +1,18 @@ +package + +public fun acceptA(/*0*/ a: A): kotlin.Unit +public fun main(/*0*/ i: I<*>): kotlin.Unit + +public open class A { + public constructor A() + 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 I { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): T? + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/starNullabilityRecursive.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/starNullabilityRecursive.kt new file mode 100644 index 00000000000..2b1566a3263 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/starNullabilityRecursive.kt @@ -0,0 +1,8 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !CHECK_TYPE +interface A?> { + fun foo(): T? +} +fun testA(a: A<*>) { + a.foo() checkType { _?>() } +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/starNullabilityRecursive.txt b/compiler/testData/diagnostics/tests/generics/projectionsScope/starNullabilityRecursive.txt new file mode 100644 index 00000000000..56b19f16002 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/starNullabilityRecursive.txt @@ -0,0 +1,10 @@ +package + +public fun testA(/*0*/ a: A<*>): kotlin.Unit + +public interface A?> { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): T? + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/superClass.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/superClass.kt new file mode 100644 index 00000000000..5acc03145cd --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/superClass.kt @@ -0,0 +1,12 @@ +// !CHECK_TYPE + +interface Clazz { + val t: T + fun getSuperClass(): Clazz +} + +fun test(clazz: Clazz<*>) { + clazz.t checkType { _() } + clazz.getSuperClass() checkType { _>() } + clazz.getSuperClass().t checkType { _() } +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/superClass.txt b/compiler/testData/diagnostics/tests/generics/projectionsScope/superClass.txt new file mode 100644 index 00000000000..3efbf66519a --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/superClass.txt @@ -0,0 +1,11 @@ +package + +public fun test(/*0*/ clazz: Clazz<*>): kotlin.Unit + +public interface Clazz { + public abstract val t: T + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun getSuperClass(): Clazz + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/typeParameterBounds.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/typeParameterBounds.kt new file mode 100644 index 00000000000..653a6e9875e --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/typeParameterBounds.kt @@ -0,0 +1,43 @@ +// !CHECK_TYPE +// !DIAGNOSTICS: -UNUSED_PARAMETER + +class Out +class In +class Inv + +class A { + fun > foo1(x: E) = 1 + fun > foo2(x: F) = 1 + fun > foo3(x: G) = 1 +} + +fun foo2(a: A, b: A) { + a.foo1(Out()) + a.foo1<Out>(Out()) + + a.foo1(Out()) + a.foo1(Out()) + + a.foo2(Inv()) + a.foo2(Inv()) + a.foo2<Inv>(Inv()) + + a.foo3(In()) + a.foo3(In()) + a.foo3>(In()) + + b.foo1(Out()) + b.foo1(Out()) + b.foo1>(Out()) + + b.foo2(Inv()) + b.foo2(Inv()) + b.foo2<Inv>(Inv()) + + + b.foo3(In()) + b.foo3<In>(In()) + + b.foo3(In()) + b.foo3(In()) +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/typeParameterBounds.txt b/compiler/testData/diagnostics/tests/generics/projectionsScope/typeParameterBounds.txt new file mode 100644 index 00000000000..9bdec591019 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/typeParameterBounds.txt @@ -0,0 +1,34 @@ +package + +public fun foo2(/*0*/ a: A, /*1*/ b: A): kotlin.Unit + +public final class A { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun > foo1(/*0*/ x: E): kotlin.Int + public final fun > foo2(/*0*/ x: F): kotlin.Int + public final fun > foo3(/*0*/ x: G): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class In { + public constructor In() + 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 Inv { + public constructor Inv() + 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 { + public constructor Out() + 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 +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceStar.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceStar.kt new file mode 100644 index 00000000000..c310b307b1b --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceStar.kt @@ -0,0 +1,9 @@ + +interface A { + fun foo(x: @UnsafeVariance K): Unit +} + +fun test(a: A<*>) { + a.foo(null) + a.foo(Any()) +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceStar.txt b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceStar.txt new file mode 100644 index 00000000000..ee021c9b089 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceStar.txt @@ -0,0 +1,10 @@ +package + +public fun test(/*0*/ a: A<*>): kotlin.Unit + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(/*0*/ x: @kotlin.UnsafeVariance() K): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/capturedTypes/memberScopeOfCaptured.kt b/compiler/testData/diagnostics/tests/inference/capturedTypes/memberScopeOfCaptured.kt index 08aada3de83..4fa525294fa 100644 --- a/compiler/testData/diagnostics/tests/inference/capturedTypes/memberScopeOfCaptured.kt +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/memberScopeOfCaptured.kt @@ -7,5 +7,6 @@ class A { fun A.bar(): A = this fun baz(x: A) { + x.bar() checkType { _>() } x.bar().foo() checkType { _() } // See KT-10448 } diff --git a/compiler/testData/diagnostics/tests/j+k/arrayOfStarParametrized.kt b/compiler/testData/diagnostics/tests/j+k/arrayOfStarParametrized.kt new file mode 100644 index 00000000000..79debb0c3f1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/arrayOfStarParametrized.kt @@ -0,0 +1,14 @@ +// !CHECK_TYPE + +// FILE: A.java +public class A { + public A[] baz() { return null; } +} + + +// FILE: main.kt + +fun foo1(x: A<*>) = x.baz() +fun foo2(x: A<*>) { + x.baz() checkType { _>>() } +} diff --git a/compiler/testData/diagnostics/tests/j+k/arrayOfStarParametrized.txt b/compiler/testData/diagnostics/tests/j+k/arrayOfStarParametrized.txt new file mode 100644 index 00000000000..65ad05bf908 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/arrayOfStarParametrized.txt @@ -0,0 +1,12 @@ +package + +public fun foo1(/*0*/ x: A<*>): kotlin.Array> +public fun foo2(/*0*/ x: A<*>): kotlin.Unit + +public open class A { + public constructor A() + public open fun baz(): kotlin.Array<(out) A!>! + 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 +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/addAllProjection.kt b/compiler/testData/diagnostics/testsWithStdLib/addAllProjection.kt new file mode 100644 index 00000000000..f9445104988 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/addAllProjection.kt @@ -0,0 +1,13 @@ +fun test(mc: MutableCollection) { + mc.addAll(mc) + + mc.addAll(arrayListOf()) + mc.addAll(arrayListOf()) + + mc.addAll(listOf("")) + mc.addAll(listOf("")) + mc.addAll(listOf("")) + + mc.addAll(emptyList()) + mc.addAll(emptyList()) +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/addAllProjection.txt b/compiler/testData/diagnostics/testsWithStdLib/addAllProjection.txt new file mode 100644 index 00000000000..5ea8d2e45c8 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/addAllProjection.txt @@ -0,0 +1,3 @@ +package + +public fun test(/*0*/ mc: kotlin.MutableCollection): kotlin.Unit diff --git a/compiler/testData/resolve/Projections.resolve b/compiler/testData/resolve/Projections.resolve index 449219ea108..3831c12fdda 100644 --- a/compiler/testData/resolve/Projections.resolve +++ b/compiler/testData/resolve/Projections.resolve @@ -18,13 +18,13 @@ class Inv() { fun testInOut() { In().`In.f:T->Unit`f("1"); (return as In).`In.f:T->Unit`f("1"); - (return as In).`In.f:Int->Int`f("1") - (return as In<*>).`In.f:Int->Int`f("1"); + (return as In).`In.f:T->Unit`f("1") + (return as In<*>).`In.f:T->Unit`f("1"); In().`In.f:Int->Int`f(1); (return as In).`In.f:Int->Int`f(1); (return as In).`In.f:Int->Int`f(1) - (return as In).`!`f1(1) + (return as In).`In.f1`f1(1) (return as In<*>).`In.f:Int->Int`f(1); Out().`Out.f(a)`f(1) @@ -39,13 +39,13 @@ fun testInOut() { Inv().`Inv.f`f(1) (return as Inv).`Inv.f`f(1) - (return as Inv).`!`f(1) - (return as Inv<*>).`!`f(1) + (return as Inv).`Inv.f`f(1) + (return as Inv<*>).`Inv.f`f(1) Inv().`Inv.inf`inf(1) (return as Inv).`Inv.inf`inf(1) - (return as Inv).`!`inf(1) - (return as Inv<*>).`!`inf(1) + (return as Inv).`Inv.inf`inf(1) + (return as Inv<*>).`Inv.inf`inf(1) Inv().`Inv.outf`outf() ((return as Inv).`Inv.outf`outf())`:kotlin::Any` diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 12074d84893..4c48eb0b875 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -7116,6 +7116,87 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { } } + @TestMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ProjectionsScope extends AbstractDiagnosticsTest { + @TestMetadata("addAll.kt") + public void testAddAll() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/addAll.kt"); + doTest(fileName); + } + + public void testAllFilesPresentInProjectionsScope() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/generics/projectionsScope"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("extensionResultSubstitution.kt") + public void testExtensionResultSubstitution() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/extensionResultSubstitution.kt"); + doTest(fileName); + } + + @TestMetadata("kt7296.kt") + public void testKt7296() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/kt7296.kt"); + doTest(fileName); + } + + @TestMetadata("kt8647.kt") + public void testKt8647() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/kt8647.kt"); + doTest(fileName); + } + + @TestMetadata("lambdaArgument.kt") + public void testLambdaArgument() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/lambdaArgument.kt"); + doTest(fileName); + } + + @TestMetadata("MLOut.kt") + public void testMLOut() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/MLOut.kt"); + doTest(fileName); + } + + @TestMetadata("recursiveUpperBoundStar.kt") + public void testRecursiveUpperBoundStar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/recursiveUpperBoundStar.kt"); + doTest(fileName); + } + + @TestMetadata("starNullability.kt") + public void testStarNullability() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/starNullability.kt"); + doTest(fileName); + } + + @TestMetadata("starNullabilityRecursive.kt") + public void testStarNullabilityRecursive() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/starNullabilityRecursive.kt"); + doTest(fileName); + } + + @TestMetadata("superClass.kt") + public void testSuperClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/superClass.kt"); + doTest(fileName); + } + + @TestMetadata("typeParameterBounds.kt") + public void testTypeParameterBounds() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/typeParameterBounds.kt"); + doTest(fileName); + } + + @TestMetadata("unsafeVarianceStar.kt") + public void testUnsafeVarianceStar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceStar.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/diagnostics/tests/generics/starProjections") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -9447,6 +9528,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("arrayOfStarParametrized.kt") + public void testArrayOfStarParametrized() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/arrayOfStarParametrized.kt"); + doTest(fileName); + } + @TestMetadata("canDeclareIfSamAdapterIsInherited.kt") public void testCanDeclareIfSamAdapterIsInherited() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/canDeclareIfSamAdapterIsInherited.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index 84365996d30..f45f25ad3b4 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -31,6 +31,12 @@ import java.util.regex.Pattern; @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestWithStdLib { + @TestMetadata("addAllProjection.kt") + public void testAddAllProjection() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/addAllProjection.kt"); + doTest(fileName); + } + public void testAllFilesPresentInTestsWithStdLib() throws Exception { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib"), Pattern.compile("^(.+)\\.kt$"), true); } diff --git a/compiler/tests/org/jetbrains/kotlin/resolve/typeApproximation/CapturedTypeApproximationTest.kt b/compiler/tests/org/jetbrains/kotlin/resolve/typeApproximation/CapturedTypeApproximationTest.kt index 290ec111629..1d3b8a5b059 100644 --- a/compiler/tests/org/jetbrains/kotlin/resolve/typeApproximation/CapturedTypeApproximationTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/resolve/typeApproximation/CapturedTypeApproximationTest.kt @@ -16,26 +16,25 @@ package org.jetbrains.kotlin.resolve.typeApproximation -import org.jetbrains.kotlin.test.KotlinLiteFixture import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment -import org.jetbrains.kotlin.test.ConfigurationKind -import java.io.File -import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.diagnostics.Severity +import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.types.TypeSubstitutor +import org.jetbrains.kotlin.resolve.calls.inference.createCapturedType +import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform +import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil +import org.jetbrains.kotlin.test.ConfigurationKind +import org.jetbrains.kotlin.test.KotlinLiteFixture +import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.types.TypeProjection import org.jetbrains.kotlin.types.TypeProjectionImpl -import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.types.Variance.* import org.jetbrains.kotlin.types.typesApproximation.approximateCapturedTypes -import org.jetbrains.kotlin.test.KotlinTestUtils -import org.jetbrains.kotlin.psi.KtPsiFactory -import org.jetbrains.kotlin.resolve.calls.inference.createCapturedType -import org.jetbrains.kotlin.diagnostics.Severity import org.jetbrains.kotlin.types.typesApproximation.approximateCapturedTypesIfNecessary -import java.util.ArrayList -import org.jetbrains.kotlin.types.TypeProjection -import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor -import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform +import java.io.File +import java.util.* public class CapturedTypeApproximationTest() : KotlinLiteFixture() { @@ -85,7 +84,7 @@ public class CapturedTypeApproximationTest() : KotlinLiteFixture() { fun createTestSubstitutor(testSubstitution: Map): TypeSubstitutor { val substitutionContext = testSubstitution.map { val (typeParameter, typeProjection) = it - typeParameter.getTypeConstructor() to TypeProjectionImpl(createCapturedType(typeProjection)) + typeParameter.typeConstructor to TypeProjectionImpl(createCapturedType(typeProjection)) }.toMap() return TypeSubstitutor.create(substitutionContext) } @@ -111,7 +110,9 @@ public class CapturedTypeApproximationTest() : KotlinLiteFixture() { val typeWithCapturedType = typeSubstitutor.substituteWithoutApproximation(TypeProjectionImpl(INVARIANT, type!!))!!.getType() val (lower, upper) = approximateCapturedTypes(typeWithCapturedType) - val substitution = approximateCapturedTypesIfNecessary(TypeProjectionImpl(INVARIANT, typeWithCapturedType)) + val substitution = + approximateCapturedTypesIfNecessary( + TypeProjectionImpl(INVARIANT, typeWithCapturedType), approximateContravariant = false) append(" ") for (typeParameter in testSubstitution.keySet()) { diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractReceiverParameterDescriptor.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractReceiverParameterDescriptor.java index 6e21f769200..5fc23f14821 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractReceiverParameterDescriptor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractReceiverParameterDescriptor.java @@ -41,7 +41,20 @@ public abstract class AbstractReceiverParameterDescriptor extends DeclarationDes @Override public ReceiverParameterDescriptor substitute(@NotNull TypeSubstitutor substitutor) { if (substitutor.isEmpty()) return this; - KotlinType substitutedType = substitutor.substitute(getType(), Variance.INVARIANT); + + KotlinType substitutedType; + if (getContainingDeclaration() instanceof ClassDescriptor) { + // Due to some reasons we check that receiver value type is a subtype of dispatch parameter + // (although we get members exactly from it's scope) + // So to make receiver with projections be a subtype of parameter's type with captured type arguments, + // we approximate latter to it's upper bound. + // See approximateDispatchReceiver.kt test for clarification + substitutedType = substitutor.substitute(getType(), Variance.OUT_VARIANCE); + } + else { + substitutedType = substitutor.substitute(getType(), Variance.INVARIANT); + } + if (substitutedType == null) return null; return new ReceiverParameterDescriptorImpl(getContainingDeclaration(), new TransientReceiver(substitutedType)); diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/CapturedTypeConstructor.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/CapturedTypeConstructor.kt index 5e43fee276a..d2e419ec1f6 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/CapturedTypeConstructor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/CapturedTypeConstructor.kt @@ -96,3 +96,34 @@ public class CapturedType( public fun createCapturedType(typeProjection: TypeProjection): KotlinType = CapturedType(typeProjection) public fun KotlinType.isCaptured(): Boolean = getConstructor() is CapturedTypeConstructor + +public fun TypeSubstitution.wrapWithCapturingSubstitution(): TypeSubstitution = + if (this is IndexedParametersSubstitution) + IndexedParametersSubstitution( + this.parameters, + this.arguments.zip(this.parameters).map { + it.first.createCapturedIfNeeded(it.second) + }.toTypedArray(), + approximateCapturedTypes = true) + else + object : DelegatedTypeSubstitution(this@wrapWithCapturingSubstitution) { + override fun approximateContravariantCapturedTypes() = true + override fun get(key: KotlinType) = super.get(key)?.createCapturedIfNeeded(key.constructor.declarationDescriptor as? TypeParameterDescriptor) + } + +private fun TypeProjection.createCapturedIfNeeded(typeParameterDescriptor: TypeParameterDescriptor?): TypeProjection { + if (typeParameterDescriptor == null || projectionKind == Variance.INVARIANT) return this + + // Treat consistent projections as invariant + if (typeParameterDescriptor.variance == projectionKind) { + // TODO: Make star projection type lazy + return if (isStarProjection) + TypeProjectionImpl(object : DelegatingType() { + override fun getDelegate() = this@createCapturedIfNeeded.type + }) + else + TypeProjectionImpl(this@createCapturedIfNeeded.type) + } + + return TypeProjectionImpl(createCapturedType(this)) +} diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt index c20546dc2bf..f3624eb84cb 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt @@ -19,29 +19,37 @@ package org.jetbrains.kotlin.resolve.scopes import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.calls.inference.wrapWithCapturingSubstitution import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.utils.Printer import org.jetbrains.kotlin.utils.newHashSetWithExpectedSize +import org.jetbrains.kotlin.utils.sure import java.util.* -public class SubstitutingScope(private val workerScope: MemberScope, private val substitutor: TypeSubstitutor) : MemberScope { +public class SubstitutingScope(private val workerScope: MemberScope, givenSubstitutor: TypeSubstitutor) : MemberScope { - private var substitutedDescriptors: MutableMap? = null + private val substitutor = givenSubstitutor.substitution.wrapWithCapturingSubstitution().buildSubstitutor() + + private var substitutedDescriptors: MutableMap? = null private val _allDescriptors by lazy { substitute(workerScope.getContributedDescriptors()) } - private fun substitute(descriptor: D?): D? { - if (descriptor == null) return null - if (substitutor.isEmpty()) return descriptor + private fun substitute(descriptor: D): D { + if (substitutor.isEmpty) return descriptor if (substitutedDescriptors == null) { - substitutedDescriptors = HashMap() + substitutedDescriptors = HashMap() } - val substituted = substitutedDescriptors!!.getOrPut(descriptor, { descriptor.substitute(substitutor) }) + val substituted = substitutedDescriptors!!.getOrPut(descriptor, { + descriptor.substitute(substitutor).sure { + "We expect that no conflict should happen while substitution is guaranteed to generate invariant projection, " + + "but $descriptor substitution fails" + } + }) @Suppress("UNCHECKED_CAST") - return substituted as D? + return substituted as D } private fun substitute(descriptors: Collection): Collection { @@ -51,9 +59,7 @@ public class SubstitutingScope(private val workerScope: MemberScope, private val val result = newHashSetWithExpectedSize(descriptors.size) for (descriptor in descriptors) { val substitute = substitute(descriptor) - if (substitute != null) { - result.add(substitute) - } + result.add(substitute) } return result @@ -61,7 +67,8 @@ public class SubstitutingScope(private val workerScope: MemberScope, private val override fun getContributedVariables(name: Name, location: LookupLocation) = substitute(workerScope.getContributedVariables(name, location)) - override fun getContributedClassifier(name: Name, location: LookupLocation) = substitute(workerScope.getContributedClassifier(name, location)) + override fun getContributedClassifier(name: Name, location: LookupLocation) = + workerScope.getContributedClassifier(name, location)?.let { substitute(it) } override fun getContributedFunctions(name: Name, location: LookupLocation) = substitute(workerScope.getContributedFunctions(name, location)) diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/CapturedTypeApproximation.kt b/core/descriptors/src/org/jetbrains/kotlin/types/CapturedTypeApproximation.kt index 56ddbafafe0..8e75ca5d6d4 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/CapturedTypeApproximation.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/CapturedTypeApproximation.kt @@ -59,7 +59,7 @@ private fun TypeProjection.toTypeArgument(typeParameter: TypeParameterDescriptor Variance.OUT_VARIANCE -> TypeArgument(typeParameter, typeParameter.builtIns.nothingType, type) } -public fun approximateCapturedTypesIfNecessary(typeProjection: TypeProjection?): TypeProjection? { +public fun approximateCapturedTypesIfNecessary(typeProjection: TypeProjection?, approximateContravariant: Boolean): TypeProjection? { if (typeProjection == null) return null if (typeProjection.isStarProjection()) return typeProjection @@ -73,10 +73,17 @@ public fun approximateCapturedTypesIfNecessary(typeProjection: TypeProjection?): val approximation = approximateCapturedTypes(type) return TypeProjectionImpl(howThisTypeIsUsed, approximation.upper) } - return substituteCapturedTypes(typeProjection) + + if (approximateContravariant) { + // TODO: assert that howThisTypeIsUsed is always IN + val approximation = approximateCapturedTypes(type).lower + return TypeProjectionImpl(howThisTypeIsUsed, approximation) + } + + return substituteCapturedTypesWithProjections(typeProjection) } -private fun substituteCapturedTypes(typeProjection: TypeProjection): TypeProjection? { +private fun substituteCapturedTypesWithProjections(typeProjection: TypeProjection): TypeProjection? { val typeSubstitutor = TypeSubstitutor.create(object : TypeConstructorSubstitution() { override fun get(key: TypeConstructor): TypeProjection? { return (key as? CapturedTypeConstructor)?.typeProjection diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/DescriptorSubstitutor.java b/core/descriptors/src/org/jetbrains/kotlin/types/DescriptorSubstitutor.java index 8b95525aa36..bee202cf7b5 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/DescriptorSubstitutor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/DescriptorSubstitutor.java @@ -67,7 +67,7 @@ public class DescriptorSubstitutor { for (TypeParameterDescriptor descriptor : typeParameters) { TypeParameterDescriptorImpl substituted = substitutedMap.get(descriptor); for (KotlinType upperBound : descriptor.getUpperBounds()) { - KotlinType substitutedBound = substitutor.substitute(upperBound, Variance.INVARIANT); + KotlinType substitutedBound = substitutor.substitute(upperBound, Variance.IN_VARIANCE); assert substitutedBound != null : "Upper bound failed to substitute: " + descriptor; substituted.addUpperBound(substitutedBound); } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/DisjointKeysUnionTypeSubstitution.kt b/core/descriptors/src/org/jetbrains/kotlin/types/DisjointKeysUnionTypeSubstitution.kt index cae2f445a01..2e6b33ab691 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/DisjointKeysUnionTypeSubstitution.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/DisjointKeysUnionTypeSubstitution.kt @@ -37,6 +37,7 @@ public class DisjointKeysUnionTypeSubstitution private constructor( override fun isEmpty() = false override fun approximateCapturedTypes() = first.approximateCapturedTypes() || second.approximateCapturedTypes() + override fun approximateContravariantCapturedTypes() = first.approximateContravariantCapturedTypes() || second.approximateContravariantCapturedTypes() override fun filterAnnotations(annotations: Annotations) = second.filterAnnotations(first.filterAnnotations(annotations)) } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt index 9e8edd10e97..df7efd01394 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.types +import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations @@ -34,6 +35,7 @@ public abstract class TypeSubstitution { open fun isEmpty(): Boolean = false open fun approximateCapturedTypes(): Boolean = false + open fun approximateContravariantCapturedTypes(): Boolean = false open fun filterAnnotations(annotations: Annotations) = annotations @@ -73,9 +75,10 @@ public abstract class TypeConstructorSubstitution : TypeSubstitution() { } } -public class IndexedParametersSubstitution private constructor( - private val parameters: Array, - private val arguments: Array +public class IndexedParametersSubstitution( + val parameters: Array, + val arguments: Array, + private val approximateCapturedTypes: Boolean = false ) : TypeSubstitution() { init { assert(parameters.size() <= arguments.size()) { @@ -89,6 +92,8 @@ public class IndexedParametersSubstitution private constructor( override fun isEmpty(): Boolean = arguments.isEmpty() + override fun approximateContravariantCapturedTypes() = approximateCapturedTypes + override fun get(key: KotlinType): TypeProjection? { val parameter = key.constructor.declarationDescriptor as? TypeParameterDescriptor ?: return null val index = parameter.index @@ -164,6 +169,7 @@ private class CompositeTypeSubstitution( override fun isEmpty() = first.isEmpty() && second.isEmpty() override fun approximateCapturedTypes() = first.approximateCapturedTypes() || second.approximateCapturedTypes() + override fun approximateContravariantCapturedTypes() = first.approximateContravariantCapturedTypes() || second.approximateContravariantCapturedTypes() override fun filterAnnotations(annotations: Annotations): Annotations = second.filterAnnotations(first.filterAnnotations(annotations)) } @@ -174,6 +180,7 @@ public open class DelegatedTypeSubstitution(val substitution: TypeSubstitution): override fun isEmpty() = substitution.isEmpty() override fun approximateCapturedTypes() = substitution.approximateCapturedTypes() + override fun approximateContravariantCapturedTypes() = substitution.approximateContravariantCapturedTypes() override fun filterAnnotations(annotations: Annotations) = substitution.filterAnnotations(annotations) } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java index 4eb64f46bd0..ba94ab40418 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java @@ -104,10 +104,11 @@ public class TypeSubstitutor { @Nullable public TypeProjection substitute(@NotNull TypeProjection typeProjection) { TypeProjection substitutedTypeProjection = substituteWithoutApproximation(typeProjection); - if (!substitution.approximateCapturedTypes()) { + if (!substitution.approximateCapturedTypes() && !substitution.approximateContravariantCapturedTypes()) { return substitutedTypeProjection; } - return CapturedTypeApproximationKt.approximateCapturedTypesIfNecessary(substitutedTypeProjection); + return CapturedTypeApproximationKt.approximateCapturedTypesIfNecessary( + substitutedTypeProjection, substitution.approximateContravariantCapturedTypes()); } @Nullable diff --git a/idea/testData/refactoring/extractFunction/basic/extensionFunForArray.kt b/idea/testData/refactoring/extractFunction/basic/extensionFunForArray.kt index 07fc8d2dbf5..137f6ab5feb 100644 --- a/idea/testData/refactoring/extractFunction/basic/extensionFunForArray.kt +++ b/idea/testData/refactoring/extractFunction/basic/extensionFunForArray.kt @@ -1,4 +1,4 @@ -// PARAM_TYPES: kotlin.Array, kotlin.Cloneable, java.io.Serializable, Any +// PARAM_TYPES: kotlin.Array, Cloneable, java.io.Serializable, Any // PARAM_DESCRIPTOR: public fun kotlin.Array.test(): kotlin.Unit defined in root package // SIBLING: fun Array.test() { diff --git a/idea/testData/refactoring/extractFunction/basic/extensionFunForArray.kt.after b/idea/testData/refactoring/extractFunction/basic/extensionFunForArray.kt.after index 4c616909b0c..28c2bf2be88 100644 --- a/idea/testData/refactoring/extractFunction/basic/extensionFunForArray.kt.after +++ b/idea/testData/refactoring/extractFunction/basic/extensionFunForArray.kt.after @@ -1,4 +1,4 @@ -// PARAM_TYPES: kotlin.Array, kotlin.Cloneable, java.io.Serializable, Any +// PARAM_TYPES: kotlin.Array, Cloneable, java.io.Serializable, Any // PARAM_DESCRIPTOR: public fun kotlin.Array.test(): kotlin.Unit defined in root package // SIBLING: fun Array.test() { diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nonNullableTypes.kt b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nonNullableTypes.kt index 21ebbc873ff..e667142210f 100644 --- a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nonNullableTypes.kt +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nonNullableTypes.kt @@ -1,4 +1,4 @@ -// PARAM_TYPES: kotlin.String, Comparable, CharSequence, java.io.Serializable, kotlin.Any +// PARAM_TYPES: kotlin.String, Comparable, CharSequence, java.io.Serializable, Any // PARAM_TYPES: X // PARAM_DESCRIPTOR: value-parameter val s: kotlin.String? defined in foo // PARAM_DESCRIPTOR: value-parameter val x: X defined in foo diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nonNullableTypes.kt.after b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nonNullableTypes.kt.after index ce94a04332e..69cbddd4a7a 100644 --- a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nonNullableTypes.kt.after +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nonNullableTypes.kt.after @@ -1,4 +1,4 @@ -// PARAM_TYPES: kotlin.String, Comparable, CharSequence, java.io.Serializable, kotlin.Any +// PARAM_TYPES: kotlin.String, Comparable, CharSequence, java.io.Serializable, Any // PARAM_TYPES: X // PARAM_DESCRIPTOR: value-parameter val s: kotlin.String? defined in foo // PARAM_DESCRIPTOR: value-parameter val x: X defined in foo diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThis.kt b/idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThis.kt index df0398e9cf8..ee309db23a8 100644 --- a/idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThis.kt +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThis.kt @@ -1,4 +1,4 @@ -// PARAM_TYPES: kotlin.String, Comparable, CharSequence, java.io.Serializable, kotlin.Any +// PARAM_TYPES: kotlin.String, Comparable, CharSequence, java.io.Serializable, Any // PARAM_DESCRIPTOR: public fun kotlin.String.test(): kotlin.Unit defined in root package fun String.foo(f: () -> Unit) { f() diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThis.kt.after b/idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThis.kt.after index ac6491623bf..b91e5d14cf0 100644 --- a/idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThis.kt.after +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThis.kt.after @@ -1,4 +1,4 @@ -// PARAM_TYPES: kotlin.String, Comparable, CharSequence, java.io.Serializable, kotlin.Any +// PARAM_TYPES: kotlin.String, Comparable, CharSequence, java.io.Serializable, Any // PARAM_DESCRIPTOR: public fun kotlin.String.test(): kotlin.Unit defined in root package fun String.foo(f: () -> Unit) { f()