diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 7a41000038e..8f8e0941ea2 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -4631,6 +4631,24 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/casts"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("arrayDowncastingContravariant.kt") + public void testArrayDowncastingContravariant() throws Exception { + runTest("compiler/testData/codegen/box/casts/arrayDowncastingContravariant.kt"); + } + + @Test + @TestMetadata("arrayDowncatingInvariant.kt") + public void testArrayDowncatingInvariant() throws Exception { + runTest("compiler/testData/codegen/box/casts/arrayDowncatingInvariant.kt"); + } + + @Test + @TestMetadata("arrayDownctingCovariant.kt") + public void testArrayDownctingCovariant() throws Exception { + runTest("compiler/testData/codegen/box/casts/arrayDownctingCovariant.kt"); + } + @Test @TestMetadata("as.kt") public void testAs() throws Exception { @@ -4757,6 +4775,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/casts/kt50577.kt"); } + @Test + @TestMetadata("kt53677.kt") + public void testKt53677() throws Exception { + runTest("compiler/testData/codegen/box/casts/kt53677.kt"); + } + @Test @TestMetadata("lambdaToUnitCast.kt") public void testLambdaToUnitCast() throws Exception { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java index 480f0f1be33..6f49b7f5cb2 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java @@ -1092,6 +1092,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/checkcast/kt22714.kt"); } + @Test + @TestMetadata("kt53465.kt") + public void testKt53465() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/checkcast/kt53465.kt"); + } + @Test @TestMetadata("noCheckcastOnDelegatingDefaultImplsCall.kt") public void testNoCheckcastOnDelegatingDefaultImplsCall() throws Exception { diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/TypeOperatorLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/TypeOperatorLowering.kt index a72905d0a7c..51cde273e0f 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/TypeOperatorLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/TypeOperatorLowering.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.ir.* import org.jetbrains.kotlin.backend.jvm.unboxInlineClass import org.jetbrains.kotlin.descriptors.DescriptorVisibilities +import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET @@ -36,6 +37,9 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext.getArgument +import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext.isTypeVariableType import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.org.objectweb.asm.Handle import org.jetbrains.org.objectweb.asm.Opcodes @@ -88,6 +92,8 @@ private class TypeOperatorLowering(private val backendContext: JvmBackendContext builder.irAs(argument, type) argument.type.isInlineClassType() && argument.type.isSubtypeOfClass(type.erasedUpperBound.symbol) -> argument + isCompatibleArrayType(argument.type, type) -> + argument type.isNullable() || argument.isDefinitelyNotNull() -> builder.irAs(argument, type) else -> { @@ -121,6 +127,22 @@ private class TypeOperatorLowering(private val backendContext: JvmBackendContext } } + private fun isCompatibleArrayType(actualType: IrType, expectedType: IrType): Boolean { + var actual = actualType + var expected = expectedType + while ((actual.isArray() || actual.isNullableArray()) && (expected.isArray() || expected.isNullableArray())) { + actual = actual.getArrayElementLowerType() + expected = expected.getArrayElementLowerType() + } + if (actual == actualType || expected == expectedType) return false + return actual.isSubtypeOfClass(expected.erasedUpperBound.symbol) + } + + private fun IrType.getArrayElementLowerType(): IrType = + if (isBoxedArray && this is IrSimpleType && (arguments.singleOrNull() as? IrTypeProjection)?.variance == Variance.IN_VARIANCE) + backendContext.irBuiltIns.anyNType + else getArrayElementType(backendContext.irBuiltIns) + // TODO extract null check elimination on IR somewhere? private fun IrExpression.isDefinitelyNotNull(): Boolean = when (this) { diff --git a/compiler/testData/codegen/box/casts/arrayDowncastingContravariant.kt b/compiler/testData/codegen/box/casts/arrayDowncastingContravariant.kt new file mode 100644 index 00000000000..162cec4cbec --- /dev/null +++ b/compiler/testData/codegen/box/casts/arrayDowncastingContravariant.kt @@ -0,0 +1,10 @@ +// TARGET_BACKEND: JVM + +inline fun f(x: Array) = x as Array + +fun box(): String = try { + f(arrayOf(42)) + "Fail" +} catch (e: Exception) { + "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/casts/arrayDowncatingInvariant.kt b/compiler/testData/codegen/box/casts/arrayDowncatingInvariant.kt new file mode 100644 index 00000000000..2964c1a1db3 --- /dev/null +++ b/compiler/testData/codegen/box/casts/arrayDowncatingInvariant.kt @@ -0,0 +1,10 @@ +// TARGET_BACKEND: JVM + +inline fun f(x: Array) = x as Array + +fun box(): String = try { + f(arrayOf(42)) + "Fail" +} catch (e: Exception) { + "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/casts/arrayDownctingCovariant.kt b/compiler/testData/codegen/box/casts/arrayDownctingCovariant.kt new file mode 100644 index 00000000000..5acb0ad539e --- /dev/null +++ b/compiler/testData/codegen/box/casts/arrayDownctingCovariant.kt @@ -0,0 +1,10 @@ +// TARGET_BACKEND: JVM + +inline fun f(x: Array) = x as Array + +fun box(): String = try { + f(arrayOf(42)) + "Fail" +} catch (e: Exception) { + "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/casts/kt48927_privateMethodOnDerivedCastToBase.kt b/compiler/testData/codegen/box/casts/kt48927_privateMethodOnDerivedCastToBase.kt index 7a9a73e1a0d..04fab3af142 100644 --- a/compiler/testData/codegen/box/casts/kt48927_privateMethodOnDerivedCastToBase.kt +++ b/compiler/testData/codegen/box/casts/kt48927_privateMethodOnDerivedCastToBase.kt @@ -2,8 +2,13 @@ abstract class Base { private fun test(): String = "OK" fun test(d: Derived): String = (d as Base).test() + + fun test(d: Array) = (d as Array)[0].test() } class Derived : Base() -fun box(): String = Derived().test(Derived()) +fun box(): String { + Derived().test(arrayOf(Derived())) + return Derived().test(Derived()) +} diff --git a/compiler/testData/codegen/box/casts/kt53677.kt b/compiler/testData/codegen/box/casts/kt53677.kt new file mode 100644 index 00000000000..9c82fddf41b --- /dev/null +++ b/compiler/testData/codegen/box/casts/kt53677.kt @@ -0,0 +1,29 @@ +// WITH_STDLIB +// WITH_COROUTINES +// DONT_TARGET_EXACT_BACKEND: JVM +// DONT_TARGET_EXACT_BACKEND: JS + +import kotlin.coroutines.* + +public inline fun myEmptyArray(): Array = arrayOfNulls(0) as Array + +inline fun Array?.myOrEmpty(): Array = this ?: myEmptyArray() + +fun runBlocking(c: suspend () -> T): T { + var res: T? = null + c.startCoroutine(Continuation(EmptyCoroutineContext) { + res = it.getOrThrow() + }) + return res!! +} + +suspend fun suspendHere(x: String) {} + +suspend fun main() { + arrayOf("1").myOrEmpty().forEach { suspendHere(it) } +} + +fun box(): String { + runBlocking(::main) + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/checkcast/kt53465.kt b/compiler/testData/codegen/bytecodeText/checkcast/kt53465.kt new file mode 100644 index 00000000000..36e6e314768 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/checkcast/kt53465.kt @@ -0,0 +1,15 @@ +// TARGET_BACKEND: JVM_IR + +public inline fun myEmptyArray(): Array = arrayOfNulls(0) as Array + +inline fun Array?.myOrEmpty(): Array = this ?: myEmptyArray() + +fun foo(a : Array?) = a.myOrEmpty() + +val a = arrayOf(1) as Array + +val b = arrayOf(1) as Array + +val c = arrayOf(arrayOf(1)) as Array?> + +// 0 CHECKCAST \ No newline at end of file diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 457f35c04b5..0e1fc3ee2ee 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -4517,6 +4517,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/casts"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @Test + @TestMetadata("arrayDowncastingContravariant.kt") + public void testArrayDowncastingContravariant() throws Exception { + runTest("compiler/testData/codegen/box/casts/arrayDowncastingContravariant.kt"); + } + + @Test + @TestMetadata("arrayDowncatingInvariant.kt") + public void testArrayDowncatingInvariant() throws Exception { + runTest("compiler/testData/codegen/box/casts/arrayDowncatingInvariant.kt"); + } + + @Test + @TestMetadata("arrayDownctingCovariant.kt") + public void testArrayDownctingCovariant() throws Exception { + runTest("compiler/testData/codegen/box/casts/arrayDownctingCovariant.kt"); + } + @Test @TestMetadata("as.kt") public void testAs() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index c1f16abafe9..1df92e31f3f 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -4631,6 +4631,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/casts"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("arrayDowncastingContravariant.kt") + public void testArrayDowncastingContravariant() throws Exception { + runTest("compiler/testData/codegen/box/casts/arrayDowncastingContravariant.kt"); + } + + @Test + @TestMetadata("arrayDowncatingInvariant.kt") + public void testArrayDowncatingInvariant() throws Exception { + runTest("compiler/testData/codegen/box/casts/arrayDowncatingInvariant.kt"); + } + + @Test + @TestMetadata("arrayDownctingCovariant.kt") + public void testArrayDownctingCovariant() throws Exception { + runTest("compiler/testData/codegen/box/casts/arrayDownctingCovariant.kt"); + } + @Test @TestMetadata("as.kt") public void testAs() throws Exception { @@ -4757,6 +4775,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/casts/kt50577.kt"); } + @Test + @TestMetadata("kt53677.kt") + public void testKt53677() throws Exception { + runTest("compiler/testData/codegen/box/casts/kt53677.kt"); + } + @Test @TestMetadata("lambdaToUnitCast.kt") public void testLambdaToUnitCast() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java index 10e1a514ab3..ff5dc544761 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java @@ -1092,6 +1092,12 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/checkcast/kt22714.kt"); } + @Test + @TestMetadata("kt53465.kt") + public void testKt53465() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/checkcast/kt53465.kt"); + } + @Test @TestMetadata("noCheckcastOnDelegatingDefaultImplsCall.kt") public void testNoCheckcastOnDelegatingDefaultImplsCall() throws Exception { diff --git a/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/D8Checker.java b/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/D8Checker.java index 2f15191e94c..27fcbd71c50 100644 --- a/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/D8Checker.java +++ b/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/D8Checker.java @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.codegen; import com.android.tools.r8.*; import com.android.tools.r8.origin.PathOrigin; +import com.android.tools.r8.utils.ExceptionDiagnostic; import kotlin.Pair; import org.jetbrains.kotlin.backend.common.output.OutputFile; import org.jetbrains.kotlin.test.KtAssert; diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 5a9de58dde1..6da7ad25b77 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -3946,6 +3946,21 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/casts"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @TestMetadata("arrayDowncastingContravariant.kt") + public void testArrayDowncastingContravariant() throws Exception { + runTest("compiler/testData/codegen/box/casts/arrayDowncastingContravariant.kt"); + } + + @TestMetadata("arrayDowncatingInvariant.kt") + public void testArrayDowncatingInvariant() throws Exception { + runTest("compiler/testData/codegen/box/casts/arrayDowncatingInvariant.kt"); + } + + @TestMetadata("arrayDownctingCovariant.kt") + public void testArrayDownctingCovariant() throws Exception { + runTest("compiler/testData/codegen/box/casts/arrayDownctingCovariant.kt"); + } + @TestMetadata("as.kt") public void testAs() throws Exception { runTest("compiler/testData/codegen/box/casts/as.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java index e42fb700b24..cbf9b9bfd85 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java @@ -3449,6 +3449,12 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/casts/kt50577.kt"); } + @Test + @TestMetadata("kt53677.kt") + public void testKt53677() throws Exception { + runTest("compiler/testData/codegen/box/casts/kt53677.kt"); + } + @Test @TestMetadata("lambdaToUnitCast.kt") public void testLambdaToUnitCast() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 8e73e4a08b4..add305c2161 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -3046,6 +3046,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest runTest("compiler/testData/codegen/box/casts/kt50577.kt"); } + @TestMetadata("kt53677.kt") + public void testKt53677() throws Exception { + runTest("compiler/testData/codegen/box/casts/kt53677.kt"); + } + @TestMetadata("lambdaToUnitCast.kt") public void testLambdaToUnitCast() throws Exception { runTest("compiler/testData/codegen/box/casts/lambdaToUnitCast.kt"); diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java index f327e127a0d..b531b875f11 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java @@ -3523,6 +3523,12 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest runTest("compiler/testData/codegen/box/casts/kt50577.kt"); } + @Test + @TestMetadata("kt53677.kt") + public void testKt53677() throws Exception { + runTest("compiler/testData/codegen/box/casts/kt53677.kt"); + } + @Test @TestMetadata("lambdaToUnitCast.kt") public void testLambdaToUnitCast() throws Exception {