JVM_IR fix cast to not-null type
We can't rely on argument type nullability here, because it still can hold an uninitialized value on JVM. KT-50577 KT-35272 KT-27427
This commit is contained in:
+6
@@ -4685,6 +4685,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/casts/kt48987.kt");
|
runTest("compiler/testData/codegen/box/casts/kt48987.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt50577.kt")
|
||||||
|
public void testKt50577() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/casts/kt50577.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("lambdaToUnitCast.kt")
|
@TestMetadata("lambdaToUnitCast.kt")
|
||||||
public void testLambdaToUnitCast() throws Exception {
|
public void testLambdaToUnitCast() throws Exception {
|
||||||
|
|||||||
+6
@@ -4686,6 +4686,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest {
|
|||||||
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/deterministicNotNullChecks.kt");
|
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/deterministicNotNullChecks.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("exclExclAsNotNullType.kt")
|
||||||
|
public void testExclExclAsNotNullType() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/exclExclAsNotNullType.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("expressionValueIsNotNull.kt")
|
@TestMetadata("expressionValueIsNotNull.kt")
|
||||||
public void testExpressionValueIsNotNull() throws Exception {
|
public void testExpressionValueIsNotNull() throws Exception {
|
||||||
|
|||||||
+26
-6
@@ -83,7 +83,11 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil
|
|||||||
private fun lowerCast(argument: IrExpression, type: IrType): IrExpression = when {
|
private fun lowerCast(argument: IrExpression, type: IrType): IrExpression = when {
|
||||||
type.isReifiedTypeParameter ->
|
type.isReifiedTypeParameter ->
|
||||||
builder.irAs(argument, type)
|
builder.irAs(argument, type)
|
||||||
argument.type.isNullable() && !type.isNullable() ->
|
argument.type.isInlineClassType() && argument.type.isSubtypeOfClass(type.erasedUpperBound.symbol) ->
|
||||||
|
argument
|
||||||
|
type.isNullable() || argument.isDefinitelyNotNull() ->
|
||||||
|
builder.irAs(argument, type)
|
||||||
|
else -> {
|
||||||
with(builder) {
|
with(builder) {
|
||||||
irLetS(argument, irType = context.irBuiltIns.anyNType) { valueSymbol ->
|
irLetS(argument, irType = context.irBuiltIns.anyNType) { valueSymbol ->
|
||||||
irIfNull(
|
irIfNull(
|
||||||
@@ -92,14 +96,30 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil
|
|||||||
irCall(throwTypeCastException).apply {
|
irCall(throwTypeCastException).apply {
|
||||||
putValueArgument(0, irString("null cannot be cast to non-null type ${type.render()}"))
|
putValueArgument(0, irString("null cannot be cast to non-null type ${type.render()}"))
|
||||||
},
|
},
|
||||||
lowerCast(irGet(valueSymbol.owner), type.makeNullable())
|
builder.irAs(irGet(valueSymbol.owner), type.makeNullable())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
argument.type.isInlineClassType() && argument.type.isSubtypeOfClass(type.erasedUpperBound.symbol) ->
|
}
|
||||||
argument
|
}
|
||||||
else ->
|
|
||||||
builder.irAs(argument, type)
|
// TODO extract null check elimination on IR somewhere?
|
||||||
|
private fun IrExpression.isDefinitelyNotNull(): Boolean =
|
||||||
|
when (this) {
|
||||||
|
is IrGetValue ->
|
||||||
|
this.symbol.owner.isDefinitelyNotNullVal()
|
||||||
|
is IrGetClass,
|
||||||
|
is IrConstructorCall ->
|
||||||
|
true
|
||||||
|
is IrCall ->
|
||||||
|
this.symbol == context.irBuiltIns.checkNotNullSymbol
|
||||||
|
else ->
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrValueDeclaration.isDefinitelyNotNullVal(): Boolean {
|
||||||
|
val irVariable = this as? IrVariable ?: return false
|
||||||
|
return !irVariable.isVar && irVariable.initializer?.isDefinitelyNotNull() == true
|
||||||
}
|
}
|
||||||
|
|
||||||
private val jvmIndyLambdaMetafactoryIntrinsic = context.ir.symbols.indyLambdaMetafactoryIntrinsic
|
private val jvmIndyLambdaMetafactoryIntrinsic = context.ir.symbols.indyLambdaMetafactoryIntrinsic
|
||||||
|
|||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
abstract class A {
|
||||||
|
abstract val x: Any
|
||||||
|
|
||||||
|
init {
|
||||||
|
castX(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B : A() {
|
||||||
|
override val x: Any = "abc"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun castX(a: A) {
|
||||||
|
a.x as String
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
try {
|
||||||
|
B()
|
||||||
|
} catch (e: NullPointerException) {
|
||||||
|
return "OK"
|
||||||
|
} catch (e: ClassCastException) {
|
||||||
|
return "OK" // JS
|
||||||
|
}
|
||||||
|
return "Failed: should throw NPE"
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
fun test(a: Any?) = a!! as String
|
||||||
|
|
||||||
|
// 1 checkNotNull
|
||||||
|
// JVM_IR_TEMPLATES
|
||||||
|
// 0 IFNULL
|
||||||
|
// 0 IFNONNULL
|
||||||
|
// 0 NullPointerException
|
||||||
|
// 0 ASTORE
|
||||||
-5
@@ -26,9 +26,4 @@ fun test3() {
|
|||||||
|
|
||||||
fun getB(): B = B()
|
fun getB(): B = B()
|
||||||
|
|
||||||
// JVM_TEMPLATES
|
|
||||||
// 1 IFNONNULL
|
// 1 IFNONNULL
|
||||||
|
|
||||||
// There should be no null checks in the bytecode.
|
|
||||||
// JVM_IR_TEMPLATES
|
|
||||||
// 0 IFNONNULL
|
|
||||||
|
|||||||
+6
@@ -4577,6 +4577,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/casts/kt48927_privateMethodOnDerivedCastToBase.kt");
|
runTest("compiler/testData/codegen/box/casts/kt48927_privateMethodOnDerivedCastToBase.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt50577.kt")
|
||||||
|
public void testKt50577() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/casts/kt50577.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("lambdaToUnitCast.kt")
|
@TestMetadata("lambdaToUnitCast.kt")
|
||||||
public void testLambdaToUnitCast() throws Exception {
|
public void testLambdaToUnitCast() throws Exception {
|
||||||
|
|||||||
+6
@@ -4536,6 +4536,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
|||||||
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/deterministicNotNullChecks.kt");
|
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/deterministicNotNullChecks.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("exclExclAsNotNullType.kt")
|
||||||
|
public void testExclExclAsNotNullType() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/exclExclAsNotNullType.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("expressionValueIsNotNull.kt")
|
@TestMetadata("expressionValueIsNotNull.kt")
|
||||||
public void testExpressionValueIsNotNull() throws Exception {
|
public void testExpressionValueIsNotNull() throws Exception {
|
||||||
|
|||||||
+6
@@ -4685,6 +4685,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/casts/kt48987.kt");
|
runTest("compiler/testData/codegen/box/casts/kt48987.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt50577.kt")
|
||||||
|
public void testKt50577() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/casts/kt50577.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("lambdaToUnitCast.kt")
|
@TestMetadata("lambdaToUnitCast.kt")
|
||||||
public void testLambdaToUnitCast() throws Exception {
|
public void testLambdaToUnitCast() throws Exception {
|
||||||
|
|||||||
+6
@@ -4686,6 +4686,12 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
|
|||||||
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/deterministicNotNullChecks.kt");
|
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/deterministicNotNullChecks.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("exclExclAsNotNullType.kt")
|
||||||
|
public void testExclExclAsNotNullType() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/exclExclAsNotNullType.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("expressionValueIsNotNull.kt")
|
@TestMetadata("expressionValueIsNotNull.kt")
|
||||||
public void testExpressionValueIsNotNull() throws Exception {
|
public void testExpressionValueIsNotNull() throws Exception {
|
||||||
|
|||||||
+5
@@ -3996,6 +3996,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/casts/kt48927_privateMethodOnDerivedCastToBase.kt");
|
runTest("compiler/testData/codegen/box/casts/kt48927_privateMethodOnDerivedCastToBase.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt50577.kt")
|
||||||
|
public void testKt50577() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/casts/kt50577.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("lambdaToUnitCast.kt")
|
@TestMetadata("lambdaToUnitCast.kt")
|
||||||
public void testLambdaToUnitCast() throws Exception {
|
public void testLambdaToUnitCast() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/casts/lambdaToUnitCast.kt");
|
runTest("compiler/testData/codegen/box/casts/lambdaToUnitCast.kt");
|
||||||
|
|||||||
+6
@@ -3371,6 +3371,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/casts/kt48927_privateMethodOnDerivedCastToBase.kt");
|
runTest("compiler/testData/codegen/box/casts/kt48927_privateMethodOnDerivedCastToBase.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt50577.kt")
|
||||||
|
public void testKt50577() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/casts/kt50577.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("lambdaToUnitCast.kt")
|
@TestMetadata("lambdaToUnitCast.kt")
|
||||||
public void testLambdaToUnitCast() throws Exception {
|
public void testLambdaToUnitCast() throws Exception {
|
||||||
|
|||||||
+6
@@ -3413,6 +3413,12 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/casts/kt48927_privateMethodOnDerivedCastToBase.kt");
|
runTest("compiler/testData/codegen/box/casts/kt48927_privateMethodOnDerivedCastToBase.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt50577.kt")
|
||||||
|
public void testKt50577() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/casts/kt50577.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("lambdaToUnitCast.kt")
|
@TestMetadata("lambdaToUnitCast.kt")
|
||||||
public void testLambdaToUnitCast() throws Exception {
|
public void testLambdaToUnitCast() throws Exception {
|
||||||
|
|||||||
+5
@@ -3016,6 +3016,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
|
|||||||
runTest("compiler/testData/codegen/box/casts/kt48927_privateMethodOnDerivedCastToBase.kt");
|
runTest("compiler/testData/codegen/box/casts/kt48927_privateMethodOnDerivedCastToBase.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt50577.kt")
|
||||||
|
public void testKt50577() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/casts/kt50577.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("lambdaToUnitCast.kt")
|
@TestMetadata("lambdaToUnitCast.kt")
|
||||||
public void testLambdaToUnitCast() throws Exception {
|
public void testLambdaToUnitCast() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/casts/lambdaToUnitCast.kt");
|
runTest("compiler/testData/codegen/box/casts/lambdaToUnitCast.kt");
|
||||||
|
|||||||
Generated
+6
@@ -3487,6 +3487,12 @@ public class ExternalTestGenerated extends AbstractExternalNativeBlackBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/casts/kt48927_privateMethodOnDerivedCastToBase.kt");
|
runTest("compiler/testData/codegen/box/casts/kt48927_privateMethodOnDerivedCastToBase.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt50577.kt")
|
||||||
|
public void testKt50577() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/casts/kt50577.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("lambdaToUnitCast.kt")
|
@TestMetadata("lambdaToUnitCast.kt")
|
||||||
public void testLambdaToUnitCast() throws Exception {
|
public void testLambdaToUnitCast() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user