diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index e89c87e4f6f..71e9301b087 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -4369,20 +4369,20 @@ The "returned" value of try expression with no finally is either the last expres } private StackValue generateIsCheck(StackValue expressionToMatch, KtTypeReference typeReference, boolean negated) { - KotlinType jetType = bindingContext.get(TYPE, typeReference); + KotlinType kotlinType = bindingContext.get(TYPE, typeReference); markStartLineNumber(typeReference); - StackValue value = generateIsCheck(expressionToMatch, jetType, false); + StackValue value = generateIsCheck(expressionToMatch, kotlinType, false); return negated ? StackValue.not(value) : value; } private StackValue generateIsCheck(StackValue expressionToGen, KotlinType kotlinType, boolean leaveExpressionOnStack) { return StackValue.operation(Type.BOOLEAN_TYPE, v -> { - expressionToGen.put(OBJECT_TYPE, null, v); + expressionToGen.put(OBJECT_TYPE, kotlinType, v); if (leaveExpressionOnStack) { v.dup(); } - Type type = boxType(asmType(kotlinType)); + Type type = boxType(typeMapper.mapTypeAsDeclaration(kotlinType)); if (TypeUtils.isReifiedTypeParameter(kotlinType)) { putReifiedOperationMarkerIfTypeIsReifiedParameter(kotlinType, ReifiedTypeInliner.OperationKind.IS); v.instanceOf(type); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index 4fa567510f0..f944dd4988e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -399,12 +399,12 @@ public abstract class StackValue { ); } - private static void unboxInlineClass(@NotNull Type type, @NotNull KotlinType kotlinType, @NotNull InstructionAdapter v) { - Type owner = KotlinTypeMapper.mapInlineClassTypeAsDeclaration(kotlinType); + private static void unboxInlineClass(@NotNull Type type, @NotNull KotlinType targetInlineClassType, @NotNull InstructionAdapter v) { + Type owner = KotlinTypeMapper.mapInlineClassTypeAsDeclaration(targetInlineClassType); coerce(type, owner, v); - Type resultType = KotlinTypeMapper.mapUnderlyingTypeOfInlineClassType(kotlinType); + Type resultType = KotlinTypeMapper.mapUnderlyingTypeOfInlineClassType(targetInlineClassType); v.invokevirtual( owner.getInternalName(), InlineClassDescriptorResolver.UNBOX_METHOD_NAME.asString(), @@ -440,25 +440,34 @@ public abstract class StackValue { @NotNull InstructionAdapter v ) { if (fromKotlinType == null || toKotlinType == null) return false; - if (!InlineClassesUtilsKt.isInlineClassType(fromKotlinType)) return false; + + boolean isFromTypeInlineClass = InlineClassesUtilsKt.isInlineClassType(fromKotlinType); + boolean isToTypeInlineClass = InlineClassesUtilsKt.isInlineClassType(toKotlinType); + + if (!isFromTypeInlineClass && !isToTypeInlineClass) return false; if (fromKotlinType.equals(toKotlinType) && fromType.equals(toType)) return true; - boolean isFromTypeUnboxed = isUnboxedInlineClass(fromKotlinType, fromType); - if (InlineClassesUtilsKt.isInlineClassType(toKotlinType)) { + if (isFromTypeInlineClass && isToTypeInlineClass) { + boolean isFromTypeUnboxed = isUnboxedInlineClass(fromKotlinType, fromType); boolean isToTypeUnboxed = isUnboxedInlineClass(toKotlinType, toType); if (isFromTypeUnboxed && !isToTypeUnboxed) { boxInlineClass(fromKotlinType, v); } else if (!isFromTypeUnboxed && isToTypeUnboxed) { - unboxInlineClass(fromType, fromKotlinType, v); + unboxInlineClass(fromType, toKotlinType, v); } } - else { - if (isFromTypeUnboxed) { + else if (isFromTypeInlineClass) { + if (isUnboxedInlineClass(fromKotlinType, fromType)) { boxInlineClass(fromKotlinType, v); } } + else { // isToTypeInlineClass is `true` + if (isUnboxedInlineClass(toKotlinType, toType)) { + unboxInlineClass(fromType, toKotlinType, v); + } + } return true; } @@ -1549,14 +1558,14 @@ public abstract class StackValue { private final ExpressionCodegen generator; public Expression(Type type, KtExpression expression, ExpressionCodegen generator) { - super(type); + super(type, generator.kotlinType(expression)); this.expression = expression; this.generator = generator; } @Override public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) { - generator.gen(expression, type); + generator.gen(expression, type, kotlinType); } } diff --git a/compiler/testData/codegen/box/inlineClasses/checkForInstanceOfInlineClass.kt b/compiler/testData/codegen/box/inlineClasses/checkForInstanceOfInlineClass.kt new file mode 100644 index 00000000000..eab47359aba --- /dev/null +++ b/compiler/testData/codegen/box/inlineClasses/checkForInstanceOfInlineClass.kt @@ -0,0 +1,55 @@ +// !LANGUAGE: +InlineClasses + +inline class UInt(val u: Int) { + override fun toString(): String { + return "UInt: $u" + } +} + +fun Any.isUInt(): Boolean = this is UInt +fun Any.notIsUInt(): Boolean = this !is UInt + +inline fun Any?.instanceOf(): Boolean = this is T + +fun UInt.extension(): String = "OK:" + +fun foo(x: UInt?): String { + if (x is UInt) { + return x.extension() + x.toString() + } + + return "fail" +} + +fun bar(x: UInt?): String { + if (x is Any) { + return x.extension() + } + + return "fail" +} + +fun box(): String { + val u = UInt(12) + if (!u.isUInt()) return "fail" + if (u.notIsUInt()) return "fail" + + if (1.isUInt()) return "fail" + if (!1.notIsUInt()) return "fail" + + + if (!u.instanceOf()) return "fail" + if (1.instanceOf()) return "fail" + + val nullableUInt: UInt? = UInt(10) + if (!nullableUInt.instanceOf()) return "fail" + + val nullAsUInt: UInt? = null + if (nullAsUInt.instanceOf()) return "fail" + if (!nullAsUInt.instanceOf()) return "fail" + + if (foo(u) != "OK:UInt: 12") return "fail" + if (bar(u) != "OK:") return "fail" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/isCheckForInlineClass.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/isCheckForInlineClass.kt new file mode 100644 index 00000000000..3b632a906f3 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/isCheckForInlineClass.kt @@ -0,0 +1,25 @@ +// !LANGUAGE: +InlineClasses + +inline class UInt(val u: Int) { + fun member() {} +} + +fun UInt?.extension() {} + +fun test(a: Any, b: Any?) { + if (a is UInt) { + a.member() + } + + if (b is UInt?) { + b.extension() + } +} + +// 2 INSTANCEOF UInt +// 1 CHECKCAST UInt + +// 1 INVOKEVIRTUAL UInt.unbox +// 2 INVOKESTATIC UInt\$Erased.member + +// 0 intValue \ 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 91b0ac94b03..ee2ce649937 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 @@ -10449,6 +10449,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("checkForInstanceOfInlineClass.kt") + public void testCheckForInstanceOfInlineClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkForInstanceOfInlineClass.kt"); + doTest(fileName); + } + @TestMetadata("checkLambdaWithInlineClassesInFunctionalType.kt") public void testCheckLambdaWithInlineClassesInFunctionalType() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkLambdaWithInlineClassesInFunctionalType.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index cf746bea24d..3e9fa04ba20 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -10449,6 +10449,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("checkForInstanceOfInlineClass.kt") + public void testCheckForInstanceOfInlineClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkForInstanceOfInlineClass.kt"); + doTest(fileName); + } + @TestMetadata("checkLambdaWithInlineClassesInFunctionalType.kt") public void testCheckLambdaWithInlineClassesInFunctionalType() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkLambdaWithInlineClassesInFunctionalType.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index e7acfa21c01..8cc6e915fdd 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1998,6 +1998,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { doTest(fileName); } + @TestMetadata("isCheckForInlineClass.kt") + public void testIsCheckForInlineClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/isCheckForInlineClass.kt"); + doTest(fileName); + } + @TestMetadata("skipCallToUnderlyingValueOfInlineClass.kt") public void testSkipCallToUnderlyingValueOfInlineClass() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/skipCallToUnderlyingValueOfInlineClass.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 64bd7a6bada..55884cf1651 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -10449,6 +10449,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("checkForInstanceOfInlineClass.kt") + public void testCheckForInstanceOfInlineClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkForInstanceOfInlineClass.kt"); + doTest(fileName); + } + @TestMetadata("checkLambdaWithInlineClassesInFunctionalType.kt") public void testCheckLambdaWithInlineClassesInFunctionalType() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkLambdaWithInlineClassesInFunctionalType.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 7a9e86d9369..2c902f0d38e 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 @@ -11433,6 +11433,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("checkForInstanceOfInlineClass.kt") + public void testCheckForInstanceOfInlineClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkForInstanceOfInlineClass.kt"); + doTest(fileName); + } + @TestMetadata("checkLambdaWithInlineClassesInFunctionalType.kt") public void testCheckLambdaWithInlineClassesInFunctionalType() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkLambdaWithInlineClassesInFunctionalType.kt");