From 5e34f290ce3438637e69d077eb9c3d244eb87596 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 24 Jan 2018 14:24:56 +0300 Subject: [PATCH] Reified 'as?' produces nullable result Previously, this was treated as a regular CHECKCAST, causing KT-22410. #Fixed KT-22410 Target versions 1.2.30 --- .../codegen/inline/ReifiedTypeInliner.kt | 2 +- .../nullCheck/NullabilityInterpreter.kt | 20 +++++++++++++++---- .../box/nullCheckOptimization/kt22410.kt | 20 +++++++++++++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 6 ++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 ++++++ .../LightAnalysisModeTestGenerated.java | 6 ++++++ .../semantics/JsCodegenBoxTestGenerated.java | 6 ++++++ 7 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 compiler/testData/codegen/box/nullCheckOptimization/kt22410.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt index d8a6c811ba3..a6a63c4c80f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt @@ -261,7 +261,7 @@ val MethodInsnNode.reificationArgument: ReificationArgument? return ReificationArgument(parameterName, nullable, arrayDepth) } -private val MethodInsnNode.operationKind: ReifiedTypeInliner.OperationKind? get() = +val MethodInsnNode.operationKind: ReifiedTypeInliner.OperationKind? get() = previous?.previous?.intConstant?.let { ReifiedTypeInliner.OperationKind.values().getOrNull(it) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/NullabilityInterpreter.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/NullabilityInterpreter.kt index 7d26d676a6f..77ff9a38c69 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/NullabilityInterpreter.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/NullabilityInterpreter.kt @@ -16,6 +16,8 @@ package org.jetbrains.kotlin.codegen.optimization.nullCheck +import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner +import org.jetbrains.kotlin.codegen.inline.operationKind import org.jetbrains.kotlin.codegen.optimization.boxing.* import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue @@ -24,6 +26,7 @@ import org.jetbrains.kotlin.codegen.pseudoInsns.isPseudo import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode +import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode import org.jetbrains.org.objectweb.asm.tree.TypeInsnNode import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue @@ -53,16 +56,25 @@ class NullabilityInterpreter : OptimizationBasicInterpreter() { val defaultResult = super.unaryOperation(insn, value) val resultType = defaultResult?.type - return when { - insn.opcode == Opcodes.CHECKCAST -> - value - insn.opcode == Opcodes.NEWARRAY || insn.opcode == Opcodes.ANEWARRAY -> + return when (insn.opcode) { + Opcodes.CHECKCAST -> + if (insn.isReifiedSafeAs()) + StrictBasicValue(resultType) + else + value + Opcodes.NEWARRAY, Opcodes.ANEWARRAY -> NotNullBasicValue(resultType) else -> defaultResult } } + private fun AbstractInsnNode.isReifiedSafeAs(): Boolean { + val marker = previous as? MethodInsnNode ?: return false + return ReifiedTypeInliner.isOperationReifiedMarker(marker) + && marker.operationKind == ReifiedTypeInliner.OperationKind.SAFE_AS + } + override fun naryOperation(insn: AbstractInsnNode, values: List): BasicValue? { val defaultResult = super.naryOperation(insn, values) val resultType = defaultResult?.type diff --git a/compiler/testData/codegen/box/nullCheckOptimization/kt22410.kt b/compiler/testData/codegen/box/nullCheckOptimization/kt22410.kt new file mode 100644 index 00000000000..05c2ca4c594 --- /dev/null +++ b/compiler/testData/codegen/box/nullCheckOptimization/kt22410.kt @@ -0,0 +1,20 @@ +fun box(): String { + defineFunc() + + func(1) + + return if (testedEquals) "OK" else "Fail" +} + +var func: (Any) -> Unit = {} + +var testedEquals = false + +inline fun defineFunc() { + func = { + val nullable = it as? T + + if (nullable == null) + testedEquals = true + } +} \ No newline at end of file diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 6310f4f2c8b..d93ce6989c1 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -12672,6 +12672,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("kt22410.kt") + public void testKt22410() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nullCheckOptimization/kt22410.kt"); + doTest(fileName); + } + @TestMetadata("kt7774.kt") public void testKt7774() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nullCheckOptimization/kt7774.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index a7736ffb75a..86122fd113c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -12672,6 +12672,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("kt22410.kt") + public void testKt22410() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nullCheckOptimization/kt22410.kt"); + doTest(fileName); + } + @TestMetadata("kt7774.kt") public void testKt7774() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nullCheckOptimization/kt7774.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index da9c16b9fe7..9dc1999de51 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -12672,6 +12672,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("kt22410.kt") + public void testKt22410() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nullCheckOptimization/kt22410.kt"); + doTest(fileName); + } + @TestMetadata("kt7774.kt") public void testKt7774() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nullCheckOptimization/kt7774.kt"); 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 e039491302e..6e9fda32bfe 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 @@ -13776,6 +13776,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("kt22410.kt") + public void testKt22410() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nullCheckOptimization/kt22410.kt"); + doTest(fileName); + } + @TestMetadata("kt7774.kt") public void testKt7774() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nullCheckOptimization/kt7774.kt");