diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index 730cea22a34..aa58bbfcf0d 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -9154,11 +9154,26 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/generics/projectionsScope/typeParameterBounds.kt"); } + @TestMetadata("unsafeVarianceInAliasedFunctionalType.kt") + public void testUnsafeVarianceInAliasedFunctionalType() throws Exception { + runTest("compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceInAliasedFunctionalType.kt"); + } + + @TestMetadata("unsafeVarianceOnInputTypeOfFunctionalType.kt") + public void testUnsafeVarianceOnInputTypeOfFunctionalType() throws Exception { + runTest("compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceOnInputTypeOfFunctionalType.kt"); + } + @TestMetadata("unsafeVarianceStar.kt") public void testUnsafeVarianceStar() throws Exception { runTest("compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceStar.kt"); } + @TestMetadata("unsafeVarianceWithRecursiveGenerics.kt") + public void testUnsafeVarianceWithRecursiveGenerics() throws Exception { + runTest("compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceWithRecursiveGenerics.kt"); + } + @TestMetadata("varargs.kt") public void testVarargs() throws Exception { runTest("compiler/testData/diagnostics/tests/generics/projectionsScope/varargs.kt"); diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 3a1e1f060c9..8f787d5a445 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -12105,6 +12105,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT public void testLastExpressionOfLambdaWithNothingConstraint() throws Exception { runTest("compiler/testData/codegen/box/inference/lastExpressionOfLambdaWithNothingConstraint.kt"); } + + @TestMetadata("unsafeVarianceCodegen.kt") + public void testUnsafeVarianceCodegen() throws Exception { + runTest("compiler/testData/codegen/box/inference/unsafeVarianceCodegen.kt"); + } } @TestMetadata("compiler/testData/codegen/box/inlineClasses") diff --git a/compiler/testData/codegen/box/inference/unsafeVarianceCodegen.kt b/compiler/testData/codegen/box/inference/unsafeVarianceCodegen.kt new file mode 100644 index 00000000000..2e415b0b9ec --- /dev/null +++ b/compiler/testData/codegen/box/inference/unsafeVarianceCodegen.kt @@ -0,0 +1,11 @@ +class A { + fun foo(x: @UnsafeVariance K): K = x +} + +fun test(a: A<*>): Any? { + return a.foo("OK") +} + +fun box(): String { + return test(A()) as String +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceInAliasedFunctionalType.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceInAliasedFunctionalType.kt new file mode 100644 index 00000000000..67afde5e957 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceInAliasedFunctionalType.kt @@ -0,0 +1,13 @@ +// FIR_IDENTICAL + +class Foo(val baz: Baz) + +class Bar { + val foo: Foo<*> = TODO() + + fun bar(): Baz { + return foo.baz + } +} + +typealias Baz = (@UnsafeVariance T) -> Unit \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceInAliasedFunctionalType.txt b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceInAliasedFunctionalType.txt new file mode 100644 index 00000000000..01f7cd0c46f --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceInAliasedFunctionalType.txt @@ -0,0 +1,19 @@ +package + +public final class Bar { + public constructor Bar() + public final val foo: Foo<*> + public final fun bar(): Baz /* = (@kotlin.UnsafeVariance T) -> kotlin.Unit */ + 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 Foo { + public constructor Foo(/*0*/ baz: Baz /* = (@kotlin.UnsafeVariance T) -> kotlin.Unit */) + public final val baz: Baz /* = (@kotlin.UnsafeVariance T) -> kotlin.Unit */ + 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 typealias Baz = (@kotlin.UnsafeVariance T) -> kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceOnInputTypeOfFunctionalType.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceOnInputTypeOfFunctionalType.kt new file mode 100644 index 00000000000..99226caf5f7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceOnInputTypeOfFunctionalType.kt @@ -0,0 +1,22 @@ +// FIR_IDENTICAL +// !DIAGNOSTICS: -UNUSED_PARAMETER -REDUNDANT_PROJECTION + +class FunctionHolder(val f: (@UnsafeVariance T) -> Unit) { + fun f2(v: @UnsafeVariance T) {} +} + +fun caller( + holder1: FunctionHolder, + holder2: FunctionHolder<*>, + holder3: FunctionHolder, + a: Any +) { + holder1.f(a) + holder1.f2(a) + + holder2.f(a) + holder2.f2(a) + + holder3.f(a) + holder3.f2(a) +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceOnInputTypeOfFunctionalType.txt b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceOnInputTypeOfFunctionalType.txt new file mode 100644 index 00000000000..e04eb5fe61e --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceOnInputTypeOfFunctionalType.txt @@ -0,0 +1,12 @@ +package + +public fun caller(/*0*/ holder1: FunctionHolder, /*1*/ holder2: FunctionHolder<*>, /*2*/ holder3: FunctionHolder, /*3*/ a: kotlin.Any): kotlin.Unit + +public final class FunctionHolder { + public constructor FunctionHolder(/*0*/ f: (@kotlin.UnsafeVariance T) -> kotlin.Unit) + public final val f: (@kotlin.UnsafeVariance T) -> kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun f2(/*0*/ v: @kotlin.UnsafeVariance T): 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/unsafeVarianceStar.fir.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceStar.fir.kt deleted file mode 100644 index 10f4635a1d4..00000000000 --- a/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceStar.fir.kt +++ /dev/null @@ -1,10 +0,0 @@ -// !WITH_NEW_INFERENCE - -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.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceStar.kt index facd768483e..ce24a2ed5a6 100644 --- a/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceStar.kt +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceStar.kt @@ -1,10 +1,10 @@ -// !WITH_NEW_INFERENCE +// FIR_IDENTICAL interface A { fun foo(x: @UnsafeVariance K): Unit } fun test(a: A<*>) { - a.foo(null) - a.foo(Any()) + a.foo(null) + a.foo(Any()) } diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceWithRecursiveGenerics.fir.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceWithRecursiveGenerics.fir.kt new file mode 100644 index 00000000000..e13533974c9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceWithRecursiveGenerics.fir.kt @@ -0,0 +1,11 @@ +interface UpdatableRendering> { + fun canUpdateFrom(another: @UnsafeVariance T): Boolean +} + +internal fun Any.matchesRendering(other: Any): Boolean { + return when { + this::class != other::class -> false + this !is UpdatableRendering<*> -> true + else -> this.canUpdateFrom(other as UpdatableRendering<*>) + } +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceWithRecursiveGenerics.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceWithRecursiveGenerics.kt new file mode 100644 index 00000000000..06f2b52c333 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceWithRecursiveGenerics.kt @@ -0,0 +1,11 @@ +interface UpdatableRendering> { + fun canUpdateFrom(another: @UnsafeVariance T): Boolean +} + +internal fun Any.matchesRendering(other: Any): Boolean { + return when { + this::class != other::class -> false + this !is UpdatableRendering<*> -> true + else -> this.canUpdateFrom(other as UpdatableRendering<*>) + } +} diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceWithRecursiveGenerics.txt b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceWithRecursiveGenerics.txt new file mode 100644 index 00000000000..41d4afd1500 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceWithRecursiveGenerics.txt @@ -0,0 +1,10 @@ +package + +internal fun kotlin.Any.matchesRendering(/*0*/ other: kotlin.Any): kotlin.Boolean + +public interface UpdatableRendering> { + public abstract fun canUpdateFrom(/*0*/ another: @kotlin.UnsafeVariance T): 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 +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index b72b48aa1d6..8db309a3585 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -9161,11 +9161,26 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali runTest("compiler/testData/diagnostics/tests/generics/projectionsScope/typeParameterBounds.kt"); } + @TestMetadata("unsafeVarianceInAliasedFunctionalType.kt") + public void testUnsafeVarianceInAliasedFunctionalType() throws Exception { + runTest("compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceInAliasedFunctionalType.kt"); + } + + @TestMetadata("unsafeVarianceOnInputTypeOfFunctionalType.kt") + public void testUnsafeVarianceOnInputTypeOfFunctionalType() throws Exception { + runTest("compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceOnInputTypeOfFunctionalType.kt"); + } + @TestMetadata("unsafeVarianceStar.kt") public void testUnsafeVarianceStar() throws Exception { runTest("compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceStar.kt"); } + @TestMetadata("unsafeVarianceWithRecursiveGenerics.kt") + public void testUnsafeVarianceWithRecursiveGenerics() throws Exception { + runTest("compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceWithRecursiveGenerics.kt"); + } + @TestMetadata("varargs.kt") public void testVarargs() throws Exception { runTest("compiler/testData/diagnostics/tests/generics/projectionsScope/varargs.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index c1c17db84b0..1aca3b95797 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -9156,11 +9156,26 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/generics/projectionsScope/typeParameterBounds.kt"); } + @TestMetadata("unsafeVarianceInAliasedFunctionalType.kt") + public void testUnsafeVarianceInAliasedFunctionalType() throws Exception { + runTest("compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceInAliasedFunctionalType.kt"); + } + + @TestMetadata("unsafeVarianceOnInputTypeOfFunctionalType.kt") + public void testUnsafeVarianceOnInputTypeOfFunctionalType() throws Exception { + runTest("compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceOnInputTypeOfFunctionalType.kt"); + } + @TestMetadata("unsafeVarianceStar.kt") public void testUnsafeVarianceStar() throws Exception { runTest("compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceStar.kt"); } + @TestMetadata("unsafeVarianceWithRecursiveGenerics.kt") + public void testUnsafeVarianceWithRecursiveGenerics() throws Exception { + runTest("compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceWithRecursiveGenerics.kt"); + } + @TestMetadata("varargs.kt") public void testVarargs() throws Exception { runTest("compiler/testData/diagnostics/tests/generics/projectionsScope/varargs.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 7da7444916b..b55a5cb6774 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -13320,6 +13320,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testLastExpressionOfLambdaWithNothingConstraint() throws Exception { runTest("compiler/testData/codegen/box/inference/lastExpressionOfLambdaWithNothingConstraint.kt"); } + + @TestMetadata("unsafeVarianceCodegen.kt") + public void testUnsafeVarianceCodegen() throws Exception { + runTest("compiler/testData/codegen/box/inference/unsafeVarianceCodegen.kt"); + } } @TestMetadata("compiler/testData/codegen/box/inlineClasses") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 26b63cfeee3..fd5e8dda73a 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -13320,6 +13320,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes public void testLastExpressionOfLambdaWithNothingConstraint() throws Exception { runTest("compiler/testData/codegen/box/inference/lastExpressionOfLambdaWithNothingConstraint.kt"); } + + @TestMetadata("unsafeVarianceCodegen.kt") + public void testUnsafeVarianceCodegen() throws Exception { + runTest("compiler/testData/codegen/box/inference/unsafeVarianceCodegen.kt"); + } } @TestMetadata("compiler/testData/codegen/box/inlineClasses") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 1040b15813d..7e6fb635db5 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -12105,6 +12105,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes public void testLastExpressionOfLambdaWithNothingConstraint() throws Exception { runTest("compiler/testData/codegen/box/inference/lastExpressionOfLambdaWithNothingConstraint.kt"); } + + @TestMetadata("unsafeVarianceCodegen.kt") + public void testUnsafeVarianceCodegen() throws Exception { + runTest("compiler/testData/codegen/box/inference/unsafeVarianceCodegen.kt"); + } } @TestMetadata("compiler/testData/codegen/box/inlineClasses") diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java index af389bed94e..b2c9a80996b 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.descriptors.annotations.CompositeAnnotations; import org.jetbrains.kotlin.descriptors.annotations.FilteredAnnotations; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.resolve.calls.inference.CapturedTypeConstructorKt; +import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor; import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker; import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt; import org.jetbrains.kotlin.types.typesApproximation.CapturedTypeApproximationKt; @@ -91,7 +92,7 @@ public class TypeSubstitutor implements TypeSubstitutorMarker { } try { - return unsafeSubstitute(new TypeProjectionImpl(howThisTypeIsUsed, type), 0).getType(); + return unsafeSubstitute(new TypeProjectionImpl(howThisTypeIsUsed, type), null, 0).getType(); } catch (SubstitutionException e) { return ErrorUtils.createErrorType(e.getMessage()); } @@ -121,14 +122,18 @@ public class TypeSubstitutor implements TypeSubstitutorMarker { } try { - return unsafeSubstitute(typeProjection, 0); + return unsafeSubstitute(typeProjection, null, 0); } catch (SubstitutionException e) { return null; } } @NotNull - private TypeProjection unsafeSubstitute(@NotNull TypeProjection originalProjection, int recursionDepth) throws SubstitutionException { + private TypeProjection unsafeSubstitute( + @NotNull TypeProjection originalProjection, + @Nullable TypeParameterDescriptor typeParameter, + int recursionDepth + ) throws SubstitutionException { assertRecursionDepth(recursionDepth, originalProjection, substitution); if (originalProjection.isStarProjection()) return originalProjection; @@ -141,6 +146,7 @@ public class TypeSubstitutor implements TypeSubstitutorMarker { TypeProjection substitution = unsafeSubstitute( new TypeProjectionImpl(originalProjection.getProjectionKind(), origin), + typeParameter, recursionDepth + 1 ); @@ -154,14 +160,27 @@ public class TypeSubstitutor implements TypeSubstitutorMarker { return originalProjection; // todo investigate } - TypeProjection replacement = substitution.get(type); + TypeProjection substituted = substitution.get(type); + TypeProjection replacement = + substituted != null ? + projectedTypeForConflictedTypeWithUnsafeVariance(type, substituted, typeParameter, originalProjection) : + null; + Variance originalProjectionKind = originalProjection.getProjectionKind(); if (replacement == null && FlexibleTypesKt.isFlexible(type) && !TypeCapabilitiesKt.isCustomTypeVariable(type)) { FlexibleType flexibleType = FlexibleTypesKt.asFlexibleType(type); TypeProjection substitutedLower = - unsafeSubstitute(new TypeProjectionImpl(originalProjectionKind, flexibleType.getLowerBound()), recursionDepth + 1); + unsafeSubstitute( + new TypeProjectionImpl(originalProjectionKind, flexibleType.getLowerBound()), + typeParameter, + recursionDepth + 1 + ); TypeProjection substitutedUpper = - unsafeSubstitute(new TypeProjectionImpl(originalProjectionKind, flexibleType.getUpperBound()), recursionDepth + 1); + unsafeSubstitute( + new TypeProjectionImpl(originalProjectionKind, flexibleType.getUpperBound()), + typeParameter, + recursionDepth + 1 + ); Variance substitutedProjectionKind = substitutedLower.getProjectionKind(); assert (substitutedProjectionKind == substitutedUpper.getProjectionKind()) && @@ -225,6 +244,37 @@ public class TypeSubstitutor implements TypeSubstitutorMarker { return substituteCompoundType(originalProjection, recursionDepth); } + @NotNull + private static TypeProjection projectedTypeForConflictedTypeWithUnsafeVariance( + @NotNull KotlinType originalType, + @NotNull TypeProjection substituted, + @Nullable TypeParameterDescriptor typeParameter, + @NotNull TypeProjection originalProjection + ) { + if (!originalType.getAnnotations().hasAnnotation(KotlinBuiltIns.FQ_NAMES.unsafeVariance)) return substituted; + + TypeConstructor constructor = substituted.getType().getConstructor(); + if (!(constructor instanceof NewCapturedTypeConstructor)) return substituted; + + NewCapturedTypeConstructor capturedType = (NewCapturedTypeConstructor) constructor; + TypeProjection capturedTypeProjection = capturedType.getProjection(); + Variance varianceOfCapturedType = capturedTypeProjection.getProjectionKind(); + + VarianceConflictType conflictWithTopLevelType = conflictType(originalProjection.getProjectionKind(), varianceOfCapturedType); + if (conflictWithTopLevelType == VarianceConflictType.OUT_IN_IN_POSITION) { + return new TypeProjectionImpl(capturedTypeProjection.getType()); + } + + if (typeParameter == null) return substituted; + + VarianceConflictType conflictTypeWithTypeParameter = conflictType(typeParameter.getVariance(), varianceOfCapturedType); + if (conflictTypeWithTypeParameter == VarianceConflictType.OUT_IN_IN_POSITION) { + return new TypeProjectionImpl(capturedTypeProjection.getType()); + } + + return substituted; + } + @NotNull private static Annotations filterOutUnsafeVariance(@NotNull Annotations annotations) { if (!annotations.hasAnnotation(KotlinBuiltIns.FQ_NAMES.unsafeVariance)) return annotations; @@ -275,7 +325,7 @@ public class TypeSubstitutor implements TypeSubstitutorMarker { TypeParameterDescriptor typeParameter = typeParameters.get(i); TypeProjection typeArgument = typeArguments.get(i); - TypeProjection substitutedTypeArgument = unsafeSubstitute(typeArgument, recursionDepth + 1); + TypeProjection substitutedTypeArgument = unsafeSubstitute(typeArgument, typeParameter, recursionDepth + 1); switch (conflictType(typeParameter.getVariance(), substitutedTypeArgument.getProjectionKind())) { case NO_CONFLICT: diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 8780dedebd5..2fdedd3de0e 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -10385,6 +10385,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { public void testLastExpressionOfLambdaWithNothingConstraint() throws Exception { runTest("compiler/testData/codegen/box/inference/lastExpressionOfLambdaWithNothingConstraint.kt"); } + + @TestMetadata("unsafeVarianceCodegen.kt") + public void testUnsafeVarianceCodegen() throws Exception { + runTest("compiler/testData/codegen/box/inference/unsafeVarianceCodegen.kt"); + } } @TestMetadata("compiler/testData/codegen/box/inlineClasses") diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index e5847b9229a..a7a886c4d20 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -10450,6 +10450,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { public void testLastExpressionOfLambdaWithNothingConstraint() throws Exception { runTest("compiler/testData/codegen/box/inference/lastExpressionOfLambdaWithNothingConstraint.kt"); } + + @TestMetadata("unsafeVarianceCodegen.kt") + public void testUnsafeVarianceCodegen() throws Exception { + runTest("compiler/testData/codegen/box/inference/unsafeVarianceCodegen.kt"); + } } @TestMetadata("compiler/testData/codegen/box/inlineClasses")