Generate is check for inline classes same as for primitives
Should be improved when inline class is based on non-null reference
This commit is contained in:
@@ -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) {
|
private StackValue generateIsCheck(StackValue expressionToMatch, KtTypeReference typeReference, boolean negated) {
|
||||||
KotlinType jetType = bindingContext.get(TYPE, typeReference);
|
KotlinType kotlinType = bindingContext.get(TYPE, typeReference);
|
||||||
markStartLineNumber(typeReference);
|
markStartLineNumber(typeReference);
|
||||||
StackValue value = generateIsCheck(expressionToMatch, jetType, false);
|
StackValue value = generateIsCheck(expressionToMatch, kotlinType, false);
|
||||||
return negated ? StackValue.not(value) : value;
|
return negated ? StackValue.not(value) : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private StackValue generateIsCheck(StackValue expressionToGen, KotlinType kotlinType, boolean leaveExpressionOnStack) {
|
private StackValue generateIsCheck(StackValue expressionToGen, KotlinType kotlinType, boolean leaveExpressionOnStack) {
|
||||||
return StackValue.operation(Type.BOOLEAN_TYPE, v -> {
|
return StackValue.operation(Type.BOOLEAN_TYPE, v -> {
|
||||||
expressionToGen.put(OBJECT_TYPE, null, v);
|
expressionToGen.put(OBJECT_TYPE, kotlinType, v);
|
||||||
if (leaveExpressionOnStack) {
|
if (leaveExpressionOnStack) {
|
||||||
v.dup();
|
v.dup();
|
||||||
}
|
}
|
||||||
|
|
||||||
Type type = boxType(asmType(kotlinType));
|
Type type = boxType(typeMapper.mapTypeAsDeclaration(kotlinType));
|
||||||
if (TypeUtils.isReifiedTypeParameter(kotlinType)) {
|
if (TypeUtils.isReifiedTypeParameter(kotlinType)) {
|
||||||
putReifiedOperationMarkerIfTypeIsReifiedParameter(kotlinType, ReifiedTypeInliner.OperationKind.IS);
|
putReifiedOperationMarkerIfTypeIsReifiedParameter(kotlinType, ReifiedTypeInliner.OperationKind.IS);
|
||||||
v.instanceOf(type);
|
v.instanceOf(type);
|
||||||
|
|||||||
@@ -399,12 +399,12 @@ public abstract class StackValue {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void unboxInlineClass(@NotNull Type type, @NotNull KotlinType kotlinType, @NotNull InstructionAdapter v) {
|
private static void unboxInlineClass(@NotNull Type type, @NotNull KotlinType targetInlineClassType, @NotNull InstructionAdapter v) {
|
||||||
Type owner = KotlinTypeMapper.mapInlineClassTypeAsDeclaration(kotlinType);
|
Type owner = KotlinTypeMapper.mapInlineClassTypeAsDeclaration(targetInlineClassType);
|
||||||
|
|
||||||
coerce(type, owner, v);
|
coerce(type, owner, v);
|
||||||
|
|
||||||
Type resultType = KotlinTypeMapper.mapUnderlyingTypeOfInlineClassType(kotlinType);
|
Type resultType = KotlinTypeMapper.mapUnderlyingTypeOfInlineClassType(targetInlineClassType);
|
||||||
v.invokevirtual(
|
v.invokevirtual(
|
||||||
owner.getInternalName(),
|
owner.getInternalName(),
|
||||||
InlineClassDescriptorResolver.UNBOX_METHOD_NAME.asString(),
|
InlineClassDescriptorResolver.UNBOX_METHOD_NAME.asString(),
|
||||||
@@ -440,25 +440,34 @@ public abstract class StackValue {
|
|||||||
@NotNull InstructionAdapter v
|
@NotNull InstructionAdapter v
|
||||||
) {
|
) {
|
||||||
if (fromKotlinType == null || toKotlinType == null) return false;
|
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;
|
if (fromKotlinType.equals(toKotlinType) && fromType.equals(toType)) return true;
|
||||||
|
|
||||||
boolean isFromTypeUnboxed = isUnboxedInlineClass(fromKotlinType, fromType);
|
if (isFromTypeInlineClass && isToTypeInlineClass) {
|
||||||
if (InlineClassesUtilsKt.isInlineClassType(toKotlinType)) {
|
boolean isFromTypeUnboxed = isUnboxedInlineClass(fromKotlinType, fromType);
|
||||||
boolean isToTypeUnboxed = isUnboxedInlineClass(toKotlinType, toType);
|
boolean isToTypeUnboxed = isUnboxedInlineClass(toKotlinType, toType);
|
||||||
if (isFromTypeUnboxed && !isToTypeUnboxed) {
|
if (isFromTypeUnboxed && !isToTypeUnboxed) {
|
||||||
boxInlineClass(fromKotlinType, v);
|
boxInlineClass(fromKotlinType, v);
|
||||||
}
|
}
|
||||||
else if (!isFromTypeUnboxed && isToTypeUnboxed) {
|
else if (!isFromTypeUnboxed && isToTypeUnboxed) {
|
||||||
unboxInlineClass(fromType, fromKotlinType, v);
|
unboxInlineClass(fromType, toKotlinType, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else if (isFromTypeInlineClass) {
|
||||||
if (isFromTypeUnboxed) {
|
if (isUnboxedInlineClass(fromKotlinType, fromType)) {
|
||||||
boxInlineClass(fromKotlinType, v);
|
boxInlineClass(fromKotlinType, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else { // isToTypeInlineClass is `true`
|
||||||
|
if (isUnboxedInlineClass(toKotlinType, toType)) {
|
||||||
|
unboxInlineClass(fromType, toKotlinType, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1549,14 +1558,14 @@ public abstract class StackValue {
|
|||||||
private final ExpressionCodegen generator;
|
private final ExpressionCodegen generator;
|
||||||
|
|
||||||
public Expression(Type type, KtExpression expression, ExpressionCodegen generator) {
|
public Expression(Type type, KtExpression expression, ExpressionCodegen generator) {
|
||||||
super(type);
|
super(type, generator.kotlinType(expression));
|
||||||
this.expression = expression;
|
this.expression = expression;
|
||||||
this.generator = generator;
|
this.generator = generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
|
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
|
||||||
generator.gen(expression, type);
|
generator.gen(expression, type, kotlinType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 <reified T> 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<UInt>()) return "fail"
|
||||||
|
if (1.instanceOf<UInt>()) return "fail"
|
||||||
|
|
||||||
|
val nullableUInt: UInt? = UInt(10)
|
||||||
|
if (!nullableUInt.instanceOf<UInt>()) return "fail"
|
||||||
|
|
||||||
|
val nullAsUInt: UInt? = null
|
||||||
|
if (nullAsUInt.instanceOf<UInt>()) return "fail"
|
||||||
|
if (!nullAsUInt.instanceOf<UInt?>()) return "fail"
|
||||||
|
|
||||||
|
if (foo(u) != "OK:UInt: 12") return "fail"
|
||||||
|
if (bar(u) != "OK:") return "fail"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+25
@@ -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
|
||||||
Generated
+6
@@ -10449,6 +10449,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("checkLambdaWithInlineClassesInFunctionalType.kt")
|
||||||
public void testCheckLambdaWithInlineClassesInFunctionalType() throws Exception {
|
public void testCheckLambdaWithInlineClassesInFunctionalType() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkLambdaWithInlineClassesInFunctionalType.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkLambdaWithInlineClassesInFunctionalType.kt");
|
||||||
|
|||||||
+6
@@ -10449,6 +10449,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("checkLambdaWithInlineClassesInFunctionalType.kt")
|
||||||
public void testCheckLambdaWithInlineClassesInFunctionalType() throws Exception {
|
public void testCheckLambdaWithInlineClassesInFunctionalType() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkLambdaWithInlineClassesInFunctionalType.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkLambdaWithInlineClassesInFunctionalType.kt");
|
||||||
|
|||||||
@@ -1998,6 +1998,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("skipCallToUnderlyingValueOfInlineClass.kt")
|
||||||
public void testSkipCallToUnderlyingValueOfInlineClass() throws Exception {
|
public void testSkipCallToUnderlyingValueOfInlineClass() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/skipCallToUnderlyingValueOfInlineClass.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/skipCallToUnderlyingValueOfInlineClass.kt");
|
||||||
|
|||||||
+6
@@ -10449,6 +10449,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("checkLambdaWithInlineClassesInFunctionalType.kt")
|
||||||
public void testCheckLambdaWithInlineClassesInFunctionalType() throws Exception {
|
public void testCheckLambdaWithInlineClassesInFunctionalType() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkLambdaWithInlineClassesInFunctionalType.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkLambdaWithInlineClassesInFunctionalType.kt");
|
||||||
|
|||||||
+6
@@ -11433,6 +11433,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("checkLambdaWithInlineClassesInFunctionalType.kt")
|
||||||
public void testCheckLambdaWithInlineClassesInFunctionalType() throws Exception {
|
public void testCheckLambdaWithInlineClassesInFunctionalType() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkLambdaWithInlineClassesInFunctionalType.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkLambdaWithInlineClassesInFunctionalType.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user