From e730965bc50670efb6ef8161b5b6f090609259c9 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Thu, 19 Dec 2019 14:27:58 +0300 Subject: [PATCH] [NI] Approximate intersection type in type argument to star if it's necessary #KT-32196 Fixed --- ...irOldFrontendDiagnosticsTestGenerated.java | 5 ++ .../kotlin/types/TypeApproximator.kt | 18 ++++ .../ifInResultOfLambda.fir.kt | 2 + .../controlStructures/ifInResultOfLambda.kt | 2 + .../ifInResultOfLambda.ni.txt | 6 ++ .../whenInResultOfLambda.fir.kt | 2 + .../controlStructures/whenInResultOfLambda.kt | 2 + .../whenInResultOfLambda.ni.txt | 8 ++ .../inference/intersectionWithEnum.fir.kt | 26 ++++++ .../tests/inference/intersectionWithEnum.kt | 26 ++++++ .../inference/intersectionWithEnum.ni.txt | 90 +++++++++++++++++++ .../tests/inference/intersectionWithEnum.txt | 90 +++++++++++++++++++ .../testsWithStdLib/kt7585/delegate.ni.txt | 2 +- .../checkers/DiagnosticsTestGenerated.java | 5 ++ .../DiagnosticsUsingJavacTestGenerated.java | 5 ++ 15 files changed, 288 insertions(+), 1 deletion(-) create mode 100644 compiler/testData/diagnostics/tests/controlStructures/ifInResultOfLambda.ni.txt create mode 100644 compiler/testData/diagnostics/tests/controlStructures/whenInResultOfLambda.ni.txt create mode 100644 compiler/testData/diagnostics/tests/inference/intersectionWithEnum.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/intersectionWithEnum.kt create mode 100644 compiler/testData/diagnostics/tests/inference/intersectionWithEnum.ni.txt create mode 100644 compiler/testData/diagnostics/tests/inference/intersectionWithEnum.txt diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index 90a80221b6d..9c076bcbb2f 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -9848,6 +9848,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/inference/intersectionTypeMultipleBoundsAsReceiver.kt"); } + @TestMetadata("intersectionWithEnum.kt") + public void testIntersectionWithEnum() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/intersectionWithEnum.kt"); + } + @TestMetadata("invokeLambdaAsFunction.kt") public void testInvokeLambdaAsFunction() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/invokeLambdaAsFunction.kt"); diff --git a/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt b/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt index 40df24883d9..a44d13e979c 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt @@ -510,6 +510,24 @@ abstract class AbstractTypeApproximator(val ctx: TypeSystemInferenceExtensionCon } } ?: continue@loop + if ( + conf.intersection != ALLOWED && + effectiveVariance == TypeVariance.OUT && + argumentType.typeConstructor().isIntersection() + ) { + var shouldReplaceWithStar = false + for (upperBoundIndex in 0 until parameter.upperBoundCount()) { + if (!AbstractTypeChecker.isSubtypeOf(ctx, approximatedArgument, parameter.getUpperBound(upperBoundIndex))) { + shouldReplaceWithStar = true + break + } + } + if (shouldReplaceWithStar) { + newArguments[index] = createStarProjection(parameter) + continue@loop + } + } + if (parameter.getVariance() == TypeVariance.INV) { newArguments[index] = createTypeArgument(approximatedArgument, effectiveVariance) } else { diff --git a/compiler/testData/diagnostics/tests/controlStructures/ifInResultOfLambda.fir.kt b/compiler/testData/diagnostics/tests/controlStructures/ifInResultOfLambda.fir.kt index 38c443697eb..e646e6e5664 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/ifInResultOfLambda.fir.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/ifInResultOfLambda.fir.kt @@ -1,4 +1,6 @@ // !WITH_NEW_INFERENCE +// NI_EXPECTED_FILE + val test1 = { if (true) 1 else "" } val test2 = { { if (true) 1 else "" } } diff --git a/compiler/testData/diagnostics/tests/controlStructures/ifInResultOfLambda.kt b/compiler/testData/diagnostics/tests/controlStructures/ifInResultOfLambda.kt index 16b80722321..ddc70e1faf6 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/ifInResultOfLambda.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/ifInResultOfLambda.kt @@ -1,4 +1,6 @@ // !WITH_NEW_INFERENCE +// NI_EXPECTED_FILE + val test1 = { if (true) 1 else "" } val test2 = { { if (true) 1 else "" } } diff --git a/compiler/testData/diagnostics/tests/controlStructures/ifInResultOfLambda.ni.txt b/compiler/testData/diagnostics/tests/controlStructures/ifInResultOfLambda.ni.txt new file mode 100644 index 00000000000..8c178e5b829 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlStructures/ifInResultOfLambda.ni.txt @@ -0,0 +1,6 @@ +package + +public val test1: () -> kotlin.Any +public val test2: () -> () -> kotlin.Any +public val test3: (kotlin.Boolean) -> kotlin.Any +public val test4: (kotlin.Boolean) -> kotlin.Any? diff --git a/compiler/testData/diagnostics/tests/controlStructures/whenInResultOfLambda.fir.kt b/compiler/testData/diagnostics/tests/controlStructures/whenInResultOfLambda.fir.kt index f7373d7a573..13d81ebf4cd 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/whenInResultOfLambda.fir.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/whenInResultOfLambda.fir.kt @@ -1,4 +1,6 @@ // !WITH_NEW_INFERENCE +// NI_EXPECTED_FILE + val test1 = { when (true) { true -> 1; else -> "" } } val test2 = { { when (true) { true -> 1; else -> "" } } } diff --git a/compiler/testData/diagnostics/tests/controlStructures/whenInResultOfLambda.kt b/compiler/testData/diagnostics/tests/controlStructures/whenInResultOfLambda.kt index ce2b57c7e50..aadd5e8df21 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/whenInResultOfLambda.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/whenInResultOfLambda.kt @@ -1,4 +1,6 @@ // !WITH_NEW_INFERENCE +// NI_EXPECTED_FILE + val test1 = { when (true) { true -> 1; else -> "" } } val test2 = { { when (true) { true -> 1; else -> "" } } } diff --git a/compiler/testData/diagnostics/tests/controlStructures/whenInResultOfLambda.ni.txt b/compiler/testData/diagnostics/tests/controlStructures/whenInResultOfLambda.ni.txt new file mode 100644 index 00000000000..c5cd166a483 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlStructures/whenInResultOfLambda.ni.txt @@ -0,0 +1,8 @@ +package + +public val test1: () -> kotlin.Any +public val test2: () -> () -> kotlin.Any +public val test3: (kotlin.Boolean) -> kotlin.Any +public val test4: (kotlin.Boolean) -> kotlin.Any? +public val test5: () -> kotlin.Unit +public fun println(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/inference/intersectionWithEnum.fir.kt b/compiler/testData/diagnostics/tests/inference/intersectionWithEnum.fir.kt new file mode 100644 index 00000000000..e186708d0f2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/intersectionWithEnum.fir.kt @@ -0,0 +1,26 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE +// NI_EXPECTED_FILE + +// ISSUE: KT-32383 + +class Inv +class Out +class In + +fun invOf(vararg t: T): Inv = null!! +fun outOf(vararg t: T): Out = null!! +fun inOf(vararg t: T): In = null!! + +interface Foo +abstract class Bar + +enum class AFoo : Foo +object A : Bar() + +enum class BFoo : Foo +object B : Bar() + +val invs = invOf(A, B) +val outs = outOf(A, B) +val ins = inOf(A, B) diff --git a/compiler/testData/diagnostics/tests/inference/intersectionWithEnum.kt b/compiler/testData/diagnostics/tests/inference/intersectionWithEnum.kt new file mode 100644 index 00000000000..e186708d0f2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/intersectionWithEnum.kt @@ -0,0 +1,26 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE +// NI_EXPECTED_FILE + +// ISSUE: KT-32383 + +class Inv +class Out +class In + +fun invOf(vararg t: T): Inv = null!! +fun outOf(vararg t: T): Out = null!! +fun inOf(vararg t: T): In = null!! + +interface Foo +abstract class Bar + +enum class AFoo : Foo +object A : Bar() + +enum class BFoo : Foo +object B : Bar() + +val invs = invOf(A, B) +val outs = outOf(A, B) +val ins = inOf(A, B) diff --git a/compiler/testData/diagnostics/tests/inference/intersectionWithEnum.ni.txt b/compiler/testData/diagnostics/tests/inference/intersectionWithEnum.ni.txt new file mode 100644 index 00000000000..f69221c5e8b --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/intersectionWithEnum.ni.txt @@ -0,0 +1,90 @@ +package + +public val ins: In> +public val invs: Inv> +public val outs: Out> +public fun inOf(/*0*/ vararg t: T /*kotlin.Array*/): In +public fun invOf(/*0*/ vararg t: T /*kotlin.Array*/): Inv +public fun outOf(/*0*/ vararg t: T /*kotlin.Array*/): Out + +public object A : Bar { + private 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 final enum class AFoo : kotlin.Enum, Foo { + private constructor AFoo() + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: AFoo): kotlin.Int + public final override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): AFoo + public final /*synthesized*/ fun values(): kotlin.Array +} + +public object B : Bar { + private constructor 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 enum class BFoo : kotlin.Enum, Foo { + private constructor BFoo() + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: BFoo): kotlin.Int + public final override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): BFoo + public final /*synthesized*/ fun values(): kotlin.Array +} + +public abstract class Bar { + public constructor Bar() + 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 Foo { + 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 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/inference/intersectionWithEnum.txt b/compiler/testData/diagnostics/tests/inference/intersectionWithEnum.txt new file mode 100644 index 00000000000..ce5f0cadfe7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/intersectionWithEnum.txt @@ -0,0 +1,90 @@ +package + +public val ins: In> +public val invs: Inv> +public val outs: Out> +public fun inOf(/*0*/ vararg t: T /*kotlin.Array*/): In +public fun invOf(/*0*/ vararg t: T /*kotlin.Array*/): Inv +public fun outOf(/*0*/ vararg t: T /*kotlin.Array*/): Out + +public object A : Bar { + private 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 final enum class AFoo : kotlin.Enum, Foo { + private constructor AFoo() + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: AFoo): kotlin.Int + public final override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): AFoo + public final /*synthesized*/ fun values(): kotlin.Array +} + +public object B : Bar { + private constructor 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 enum class BFoo : kotlin.Enum, Foo { + private constructor BFoo() + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: BFoo): kotlin.Int + public final override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): BFoo + public final /*synthesized*/ fun values(): kotlin.Array +} + +public abstract class Bar { + public constructor Bar() + 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 Foo { + 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 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/testsWithStdLib/kt7585/delegate.ni.txt b/compiler/testData/diagnostics/testsWithStdLib/kt7585/delegate.ni.txt index 6989b64f912..96957778aa1 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/kt7585/delegate.ni.txt +++ b/compiler/testData/diagnostics/testsWithStdLib/kt7585/delegate.ni.txt @@ -39,7 +39,7 @@ public final class ExoticWrapper : Wrapper { public final class My { public constructor My(/*0*/ x: kotlin.Int) - public final val wrapper: Wrapper! + public final val wrapper: Wrapper<*>! public final val x: kotlin.Int public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 21f1ff931f4..225cb72189f 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -9855,6 +9855,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/inference/intersectionTypeMultipleBoundsAsReceiver.kt"); } + @TestMetadata("intersectionWithEnum.kt") + public void testIntersectionWithEnum() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/intersectionWithEnum.kt"); + } + @TestMetadata("invokeLambdaAsFunction.kt") public void testInvokeLambdaAsFunction() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/invokeLambdaAsFunction.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index f4c8ea04489..6a9289568c6 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -9850,6 +9850,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/inference/intersectionTypeMultipleBoundsAsReceiver.kt"); } + @TestMetadata("intersectionWithEnum.kt") + public void testIntersectionWithEnum() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/intersectionWithEnum.kt"); + } + @TestMetadata("invokeLambdaAsFunction.kt") public void testInvokeLambdaAsFunction() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/invokeLambdaAsFunction.kt");