From bda5bab0571281f5fb88a56d4f6b70666ed8ecad Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Mon, 15 Dec 2014 22:54:52 +0300 Subject: [PATCH] Captured type might be substituted in an opposite projection out Captured (in Int) = out Int in Captured (out Int) = in Int --- ...edTypeSubstitutedIntoOppositeProjection.kt | 14 ++++++ ...dTypeSubstitutedIntoOppositeProjection.txt | 6 +++ .../checkers/JetDiagnosticsTestGenerated.java | 6 +++ .../jet/lang/types/TypeSubstitutor.java | 49 +++++++++++-------- 4 files changed, 55 insertions(+), 20 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/inference/capturedTypes/capturedTypeSubstitutedIntoOppositeProjection.kt create mode 100644 compiler/testData/diagnostics/tests/inference/capturedTypes/capturedTypeSubstitutedIntoOppositeProjection.txt diff --git a/compiler/testData/diagnostics/tests/inference/capturedTypes/capturedTypeSubstitutedIntoOppositeProjection.kt b/compiler/testData/diagnostics/tests/inference/capturedTypes/capturedTypeSubstitutedIntoOppositeProjection.kt new file mode 100644 index 00000000000..e64ae9c4613 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/capturedTypeSubstitutedIntoOppositeProjection.kt @@ -0,0 +1,14 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !CHECK_TYPE + +fun foo1(a1: Array, a2: Array): T = null!! + +fun test1(a1: Array, a2: Array) { + foo1(a1, a2) checkType { it : _ } +} + +fun foo2(a1: Array, a2: Array): T = null!! + +fun test2(a1: Array, a2: Array) { + foo2(a1, a2) checkType { it : _} +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/capturedTypes/capturedTypeSubstitutedIntoOppositeProjection.txt b/compiler/testData/diagnostics/tests/inference/capturedTypes/capturedTypeSubstitutedIntoOppositeProjection.txt new file mode 100644 index 00000000000..bde310d0938 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/capturedTypeSubstitutedIntoOppositeProjection.txt @@ -0,0 +1,6 @@ +package + +internal fun foo1(/*0*/ a1: kotlin.Array, /*1*/ a2: kotlin.Array): T +internal fun foo2(/*0*/ a1: kotlin.Array, /*1*/ a2: kotlin.Array): T +internal fun test1(/*0*/ a1: kotlin.Array, /*1*/ a2: kotlin.Array): kotlin.Unit +internal fun test2(/*0*/ a1: kotlin.Array, /*1*/ a2: kotlin.Array): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 2f0e333fa5c..00a7824d7d0 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -5136,6 +5136,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("capturedTypeSubstitutedIntoOppositeProjection.kt") + public void testCapturedTypeSubstitutedIntoOppositeProjection() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedTypeSubstitutedIntoOppositeProjection.kt"); + doTest(fileName); + } + @TestMetadata("kt2570.kt") public void testKt2570() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/kt2570.kt"); diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java b/core/descriptors/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java index 45376b22f43..cb2b818e24e 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java @@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.types; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; +import org.jetbrains.jet.lang.resolve.calls.inference.InferencePackage; import org.jetbrains.jet.lang.resolve.scopes.SubstitutingScope; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lang.types.typeUtil.TypeUtilPackage; @@ -186,28 +187,36 @@ public class TypeSubstitutor { TypeProjection replacement = substitution.get(type.getConstructor()); if (replacement != null) { - switch (conflictType(originalProjectionKind, replacement.getProjectionKind())) { - case OUT_IN_IN_POSITION: - throw new SubstitutionException("Out-projection in in-position"); - case IN_IN_OUT_POSITION: - // todo use the right type parameter variance and upper bound - return new TypeProjectionImpl(Variance.OUT_VARIANCE, KotlinBuiltIns.getInstance().getNullableAnyType()); - case NO_CONFLICT: - JetType substitutedType; - CustomTypeVariable typeVariable = TypesPackage.getCustomTypeVariable(type); - if (typeVariable != null) { - substitutedType = typeVariable.substitutionResult(replacement.getType()); - } - else { - // this is a simple type T or T?: if it's T, we should just take replacement, if T? - we make replacement nullable - substitutedType = TypeUtils.makeNullableIfNeeded(replacement.getType(), type.isMarkedNullable()); - } + VarianceConflictType varianceConflict = conflictType(originalProjectionKind, replacement.getProjectionKind()); - Variance resultingProjectionKind = combine(originalProjectionKind, replacement.getProjectionKind()); - return new TypeProjectionImpl(resultingProjectionKind, substitutedType); - default: - throw new IllegalStateException(); + // Captured type might be substituted in an opposite projection: + // out 'Captured (in Int)' = out Int + // in 'Captured (out Int)' = in Int + boolean allowVarianceConflict = InferencePackage.isCaptured(type); + if (!allowVarianceConflict) { + //noinspection EnumSwitchStatementWhichMissesCases + switch (varianceConflict) { + case OUT_IN_IN_POSITION: + throw new SubstitutionException("Out-projection in in-position"); + case IN_IN_OUT_POSITION: + // todo use the right type parameter variance and upper bound + return new TypeProjectionImpl(Variance.OUT_VARIANCE, KotlinBuiltIns.getInstance().getNullableAnyType()); + } } + JetType substitutedType; + CustomTypeVariable typeVariable = TypesPackage.getCustomTypeVariable(type); + if (typeVariable != null) { + substitutedType = typeVariable.substitutionResult(replacement.getType()); + } + else { + // this is a simple type T or T?: if it's T, we should just take replacement, if T? - we make replacement nullable + substitutedType = TypeUtils.makeNullableIfNeeded(replacement.getType(), type.isMarkedNullable()); + } + + Variance resultingProjectionKind = varianceConflict == VarianceConflictType.NO_CONFLICT + ? combine(originalProjectionKind, replacement.getProjectionKind()) + : originalProjectionKind; + return new TypeProjectionImpl(resultingProjectionKind, substitutedType); } // The type is not within the substitution range, i.e. Foo, Bar etc. return substituteCompoundType(originalProjection, recursionDepth);