diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java index 2b1b7045986..281dcec21ed 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java @@ -72,13 +72,9 @@ public class OptimizationBasicInterpreter extends Interpreter implem @Override public BasicValue newOperation(@NotNull AbstractInsnNode insn) throws AnalyzerException { - if (insn.getOpcode() == Opcodes.ACONST_NULL) { - return newValue(Type.getObjectType("java/lang/Object")); - } - switch (insn.getOpcode()) { case ACONST_NULL: - return newValue(Type.getObjectType("null")); + return NULL_VALUE; case ICONST_M1: case ICONST_0: case ICONST_1: @@ -362,6 +358,9 @@ public class OptimizationBasicInterpreter extends Interpreter implem // if merge of two references then `lub` is java/lang/Object // arrays also are BasicValues with reference type's if (isReference(v) && isReference(w)) { + if (v == NULL_VALUE) return newValue(w.getType()); + if (w == NULL_VALUE) return newValue(v.getType()); + return StrictBasicValue.REFERENCE_VALUE; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/StrictBasicValue.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/StrictBasicValue.kt index 0038fb65ad8..8a9d736a7c7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/StrictBasicValue.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/StrictBasicValue.kt @@ -45,6 +45,9 @@ open class StrictBasicValue(type: Type?) : BasicValue(type) { val SHORT_VALUE = StrictBasicValue(Type.SHORT_TYPE) @JvmField val REFERENCE_VALUE = StrictBasicValue(Type.getObjectType("java/lang/Object")) + + @JvmField + val NULL_VALUE = StrictBasicValue(Type.getObjectType("java/lang/Object")) } override fun equals(other: Any?): Boolean { @@ -60,4 +63,9 @@ open class StrictBasicValue(type: Type?) : BasicValue(type) { } override fun hashCode() = (type?.hashCode() ?: 0) + + override fun toString(): String { + if (this === UNINITIALIZED_VALUE) return "." + return super.toString() + } } diff --git a/compiler/testData/codegen/box/coroutines/mergeNullAndString.kt b/compiler/testData/codegen/box/coroutines/mergeNullAndString.kt new file mode 100644 index 00000000000..5dff958abf9 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/mergeNullAndString.kt @@ -0,0 +1,38 @@ +// WITH_RUNTIME +// WITH_COROUTINES +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +var res = "" + +suspend fun foo(y: A?): String { + val origin: String? = y?.z + if (origin != null) { + baz(origin) + baz(origin) + } + + return res +} + +suspend fun baz(y: String): Unit = suspendCoroutineOrReturn { x -> + res += y[res.length] + x.resume(Unit) + COROUTINE_SUSPENDED +} + +class A(val z: String) + +fun box(): String { + var result = "" + + builder { + result = foo(A("OK")) + } + + return result +} diff --git a/compiler/testData/codegen/light-analysis/coroutines/mergeNullAndString.txt b/compiler/testData/codegen/light-analysis/coroutines/mergeNullAndString.txt new file mode 100644 index 00000000000..b5b9eb1baca --- /dev/null +++ b/compiler/testData/codegen/light-analysis/coroutines/mergeNullAndString.txt @@ -0,0 +1,42 @@ +@kotlin.Metadata +public final class A { + private final @org.jetbrains.annotations.NotNull field z: java.lang.String + public method (@org.jetbrains.annotations.NotNull p0: java.lang.String): void + public final @org.jetbrains.annotations.NotNull method getZ(): java.lang.String +} + +@kotlin.Metadata +public final class CoroutineUtilKt { + public final static @org.jetbrains.annotations.NotNull method handleExceptionContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.experimental.Continuation + public final static @org.jetbrains.annotations.NotNull method handleResultContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.experimental.Continuation +} + +@kotlin.Metadata +public class EmptyContinuation { + public final static field Companion: EmptyContinuation.Companion + private final @org.jetbrains.annotations.NotNull field context: kotlin.coroutines.experimental.CoroutineContext + inner class EmptyContinuation/Companion + public @synthetic.kotlin.jvm.GeneratedByJvmOverloads method (): void + public method (@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.CoroutineContext): void + public synthetic method (p0: kotlin.coroutines.experimental.CoroutineContext, p1: int, p2: kotlin.jvm.internal.DefaultConstructorMarker): void + public @org.jetbrains.annotations.NotNull method getContext(): kotlin.coroutines.experimental.CoroutineContext + public method resume(@org.jetbrains.annotations.Nullable p0: java.lang.Object): void + public method resumeWithException(@org.jetbrains.annotations.NotNull p0: java.lang.Throwable): void +} + +@kotlin.Metadata +public final static class EmptyContinuation/Companion { + inner class EmptyContinuation/Companion + private method (): void +} + +@kotlin.Metadata +public final class MergeNullAndStringKt { + private static @org.jetbrains.annotations.NotNull field res: java.lang.String + public final static @org.jetbrains.annotations.Nullable method baz(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object + public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String + public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): void + public final static @org.jetbrains.annotations.Nullable method foo(@org.jetbrains.annotations.Nullable p0: A, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object + public final static @org.jetbrains.annotations.NotNull method getRes(): java.lang.String + public final static method setRes(@org.jetbrains.annotations.NotNull p0: java.lang.String): void +} 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 06cb0b741e2..3d08a308905 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 @@ -4799,6 +4799,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("mergeNullAndString.kt") + public void testMergeNullAndString() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/mergeNullAndString.kt"); + doTest(fileName); + } + @TestMetadata("multipleInvokeCalls.kt") public void testMultipleInvokeCalls() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multipleInvokeCalls.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index e014b68eeab..9ae0e69d857 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -4799,6 +4799,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("mergeNullAndString.kt") + public void testMergeNullAndString() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/mergeNullAndString.kt"); + doTest(fileName); + } + @TestMetadata("multipleInvokeCalls.kt") public void testMultipleInvokeCalls() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multipleInvokeCalls.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java index adc77e70688..4f6688180c1 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java @@ -4799,6 +4799,12 @@ public class LightAnalysisModeCodegenTestGenerated extends AbstractLightAnalysis doTest(fileName); } + @TestMetadata("mergeNullAndString.kt") + public void testMergeNullAndString() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/mergeNullAndString.kt"); + doTest(fileName); + } + @TestMetadata("multipleInvokeCalls.kt") public void testMultipleInvokeCalls() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multipleInvokeCalls.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 eea89f8ae3a..5133e1f58d3 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 @@ -5490,6 +5490,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("mergeNullAndString.kt") + public void testMergeNullAndString() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/mergeNullAndString.kt"); + doTest(fileName); + } + @TestMetadata("multipleInvokeCalls.kt") public void testMultipleInvokeCalls() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multipleInvokeCalls.kt");