Desugar constructor call of inline class to the underlying value
Also add information about KotlinType to the constant stack values
This commit is contained in:
@@ -745,7 +745,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
public StackValue visitConstantExpression(@NotNull KtConstantExpression expression, StackValue receiver) {
|
||||
ConstantValue<?> compileTimeValue = getPrimitiveOrStringCompileTimeConstant(expression);
|
||||
assert compileTimeValue != null;
|
||||
return StackValue.constant(compileTimeValue.getValue(), expressionType(expression));
|
||||
return StackValue.constant(compileTimeValue.getValue(), expressionType(expression), kotlinType(expression));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -2093,7 +2093,16 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
KtValueArgument valueArgument = CollectionsKt.firstOrNull(expression.getValueArguments());
|
||||
if (valueArgument == null) return null;
|
||||
|
||||
return gen(valueArgument.getArgumentExpression());
|
||||
SimpleType inlineClassType = ((ClassDescriptor) descriptor.getContainingDeclaration()).getDefaultType();
|
||||
|
||||
Type underlyingType = typeMapper.mapType(inlineClassType);
|
||||
KotlinType underlyingKotlinType = InlineClassesUtilsKt.unsubstitutedUnderlyingType(inlineClassType);
|
||||
|
||||
StackValue argumentValue = gen(valueArgument.getArgumentExpression());
|
||||
|
||||
return StackValue.coercionValueForArgumentOfInlineClassConstructor(
|
||||
argumentValue, underlyingType, inlineClassType, underlyingKotlinType
|
||||
);
|
||||
}
|
||||
|
||||
return generateNewCall(expression, resolvedCall);
|
||||
|
||||
@@ -204,12 +204,17 @@ public abstract class StackValue {
|
||||
|
||||
@NotNull
|
||||
public static StackValue constant(@Nullable Object value, @NotNull Type type) {
|
||||
return constant(value, type, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static StackValue constant(@Nullable Object value, @NotNull Type type, @Nullable KotlinType kotlinType) {
|
||||
if (type == Type.BOOLEAN_TYPE) {
|
||||
assert value instanceof Boolean : "Value for boolean constant should have boolean type: " + value;
|
||||
return BranchedValue.Companion.booleanConstant((Boolean) value);
|
||||
}
|
||||
else {
|
||||
return new Constant(value, type);
|
||||
return new Constant(value, type, kotlinType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,10 +572,21 @@ public abstract class StackValue {
|
||||
}
|
||||
|
||||
public static StackValue coercion(@NotNull StackValue value, @NotNull Type castType, @Nullable KotlinType castKotlinType) {
|
||||
if (value.type.equals(castType)) {
|
||||
return coercionValueForArgumentOfInlineClassConstructor(value, castType, castKotlinType, null);
|
||||
}
|
||||
|
||||
public static StackValue coercionValueForArgumentOfInlineClassConstructor(
|
||||
@NotNull StackValue value,
|
||||
@NotNull Type castType,
|
||||
@Nullable KotlinType castKotlinType,
|
||||
@Nullable KotlinType underlyingKotlinType
|
||||
) {
|
||||
boolean kotlinTypesAreEqual = value.kotlinType == null && castKotlinType == null ||
|
||||
value.kotlinType != null && castKotlinType != null && castKotlinType.equals(value.kotlinType);
|
||||
if (value.type.equals(castType) && kotlinTypesAreEqual) {
|
||||
return value;
|
||||
}
|
||||
return new CoercionValue(value, castType, castKotlinType);
|
||||
return new CoercionValue(value, castType, castKotlinType, underlyingKotlinType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -925,8 +941,8 @@ public abstract class StackValue {
|
||||
@Nullable
|
||||
public final Object value;
|
||||
|
||||
public Constant(@Nullable Object value, Type type) {
|
||||
super(type, false);
|
||||
public Constant(@Nullable Object value, Type type, KotlinType kotlinType) {
|
||||
super(type, kotlinType, false);
|
||||
assert !Type.BOOLEAN_TYPE.equals(type) : "Boolean constants should be created via 'StackValue.constant'";
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@@ -23,12 +23,20 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
class CoercionValue(
|
||||
val value: StackValue,
|
||||
private val castType: Type,
|
||||
private val castKotlinType: KotlinType?
|
||||
) : StackValue(castType, value.canHaveSideEffects()) {
|
||||
private val castKotlinType: KotlinType?,
|
||||
private val underlyingKotlinType: KotlinType? // type of the underlying parameter for inline class
|
||||
) : StackValue(castType, castKotlinType, value.canHaveSideEffects()) {
|
||||
|
||||
override fun putSelector(type: Type, kotlinType: KotlinType?, v: InstructionAdapter) {
|
||||
value.putSelector(value.type, value.kotlinType, v)
|
||||
StackValue.coerce(value.type, value.kotlinType, castType, castKotlinType, v)
|
||||
|
||||
// consider the following example:
|
||||
|
||||
// inline class AsAny(val a: Any)
|
||||
// val a = AsAny(1)
|
||||
//
|
||||
// Here we should coerce `Int` (1) to `Any` and remember that resulting type is inline class type `AsAny` (not `Any`)
|
||||
StackValue.coerce(value.type, value.kotlinType, castType, underlyingKotlinType ?: castKotlinType, v)
|
||||
StackValue.coerce(castType, castKotlinType, type, kotlinType, v)
|
||||
}
|
||||
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
|
||||
inline class AsInt(val value: Int) {
|
||||
override fun toString(): String {
|
||||
return "asInt: ${value.toString()}"
|
||||
}
|
||||
}
|
||||
|
||||
inline class AsAny(val value: Any) {
|
||||
override fun toString(): String {
|
||||
return "asAny: ${value.toString()}"
|
||||
}
|
||||
}
|
||||
|
||||
fun takeAny(a: Any): String = a.toString()
|
||||
|
||||
fun getInt(): Int = 10
|
||||
fun <T> id(x: T) = x
|
||||
|
||||
fun box(): String {
|
||||
if (takeAny(AsInt(123)) != "asInt: 123") return "fail"
|
||||
if (takeAny(AsAny(321)) != "asAny: 321") return "fail"
|
||||
|
||||
if (takeAny(AsInt(getInt())) != "asInt: 10") return "fail"
|
||||
if (takeAny(AsInt(id(20))) != "asInt: 20") return "fail"
|
||||
|
||||
if (takeAny(AsAny(id(30))) != "asAny: 30") return "fail"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
|
||||
inline class AsInt(val value: Int)
|
||||
inline class AsAny(val value: Any)
|
||||
|
||||
fun takeAny(a: Any) {}
|
||||
|
||||
fun test() {
|
||||
takeAny(AsInt(123)) // box
|
||||
takeAny(AsAny(123)) // box int, box inline class
|
||||
}
|
||||
|
||||
// 1 INVOKESTATIC AsInt\$Erased.box
|
||||
// 0 INVOKEVIRTUAL AsInt.unbox
|
||||
|
||||
// 1 INVOKESTATIC AsAny\$Erased.box
|
||||
// 0 INVOKEVIRTUAL AsAny.unbox
|
||||
|
||||
// 1 valueOf
|
||||
// 0 intValue
|
||||
Generated
+6
@@ -10431,6 +10431,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("createInlineClassInArgumentPosition.kt")
|
||||
public void testCreateInlineClassInArgumentPosition() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/createInlineClassInArgumentPosition.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("emptyConstructorForInlineClass.kt")
|
||||
public void testEmptyConstructorForInlineClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/emptyConstructorForInlineClass.kt");
|
||||
|
||||
+6
@@ -10431,6 +10431,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("createInlineClassInArgumentPosition.kt")
|
||||
public void testCreateInlineClassInArgumentPosition() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/createInlineClassInArgumentPosition.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("emptyConstructorForInlineClass.kt")
|
||||
public void testEmptyConstructorForInlineClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/emptyConstructorForInlineClass.kt");
|
||||
|
||||
@@ -1914,6 +1914,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("boxResultAfterConstructorCall.kt")
|
||||
public void testBoxResultAfterConstructorCall() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/boxResultAfterConstructorCall.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("boxUnboxInlineClassFromMethodReturnType.kt")
|
||||
public void testBoxUnboxInlineClassFromMethodReturnType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxInlineClassFromMethodReturnType.kt");
|
||||
|
||||
+6
@@ -10431,6 +10431,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("createInlineClassInArgumentPosition.kt")
|
||||
public void testCreateInlineClassInArgumentPosition() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/createInlineClassInArgumentPosition.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("emptyConstructorForInlineClass.kt")
|
||||
public void testEmptyConstructorForInlineClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/emptyConstructorForInlineClass.kt");
|
||||
|
||||
+6
@@ -11415,6 +11415,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("createInlineClassInArgumentPosition.kt")
|
||||
public void testCreateInlineClassInArgumentPosition() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/createInlineClassInArgumentPosition.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("emptyConstructorForInlineClass.kt")
|
||||
public void testEmptyConstructorForInlineClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/emptyConstructorForInlineClass.kt");
|
||||
|
||||
Reference in New Issue
Block a user