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) {
|
public StackValue visitConstantExpression(@NotNull KtConstantExpression expression, StackValue receiver) {
|
||||||
ConstantValue<?> compileTimeValue = getPrimitiveOrStringCompileTimeConstant(expression);
|
ConstantValue<?> compileTimeValue = getPrimitiveOrStringCompileTimeConstant(expression);
|
||||||
assert compileTimeValue != null;
|
assert compileTimeValue != null;
|
||||||
return StackValue.constant(compileTimeValue.getValue(), expressionType(expression));
|
return StackValue.constant(compileTimeValue.getValue(), expressionType(expression), kotlinType(expression));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -2093,7 +2093,16 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
KtValueArgument valueArgument = CollectionsKt.firstOrNull(expression.getValueArguments());
|
KtValueArgument valueArgument = CollectionsKt.firstOrNull(expression.getValueArguments());
|
||||||
if (valueArgument == null) return null;
|
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);
|
return generateNewCall(expression, resolvedCall);
|
||||||
|
|||||||
@@ -204,12 +204,17 @@ public abstract class StackValue {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static StackValue constant(@Nullable Object value, @NotNull Type type) {
|
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) {
|
if (type == Type.BOOLEAN_TYPE) {
|
||||||
assert value instanceof Boolean : "Value for boolean constant should have boolean type: " + value;
|
assert value instanceof Boolean : "Value for boolean constant should have boolean type: " + value;
|
||||||
return BranchedValue.Companion.booleanConstant((Boolean) value);
|
return BranchedValue.Companion.booleanConstant((Boolean) value);
|
||||||
}
|
}
|
||||||
else {
|
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) {
|
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 value;
|
||||||
}
|
}
|
||||||
return new CoercionValue(value, castType, castKotlinType);
|
return new CoercionValue(value, castType, castKotlinType, underlyingKotlinType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -925,8 +941,8 @@ public abstract class StackValue {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public final Object value;
|
public final Object value;
|
||||||
|
|
||||||
public Constant(@Nullable Object value, Type type) {
|
public Constant(@Nullable Object value, Type type, KotlinType kotlinType) {
|
||||||
super(type, false);
|
super(type, kotlinType, false);
|
||||||
assert !Type.BOOLEAN_TYPE.equals(type) : "Boolean constants should be created via 'StackValue.constant'";
|
assert !Type.BOOLEAN_TYPE.equals(type) : "Boolean constants should be created via 'StackValue.constant'";
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,12 +23,20 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
|||||||
class CoercionValue(
|
class CoercionValue(
|
||||||
val value: StackValue,
|
val value: StackValue,
|
||||||
private val castType: Type,
|
private val castType: Type,
|
||||||
private val castKotlinType: KotlinType?
|
private val castKotlinType: KotlinType?,
|
||||||
) : StackValue(castType, value.canHaveSideEffects()) {
|
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) {
|
override fun putSelector(type: Type, kotlinType: KotlinType?, v: InstructionAdapter) {
|
||||||
value.putSelector(value.type, value.kotlinType, v)
|
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)
|
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);
|
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")
|
@TestMetadata("emptyConstructorForInlineClass.kt")
|
||||||
public void testEmptyConstructorForInlineClass() throws Exception {
|
public void testEmptyConstructorForInlineClass() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/emptyConstructorForInlineClass.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/emptyConstructorForInlineClass.kt");
|
||||||
|
|||||||
+6
@@ -10431,6 +10431,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("emptyConstructorForInlineClass.kt")
|
||||||
public void testEmptyConstructorForInlineClass() throws Exception {
|
public void testEmptyConstructorForInlineClass() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/emptyConstructorForInlineClass.kt");
|
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);
|
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")
|
@TestMetadata("boxUnboxInlineClassFromMethodReturnType.kt")
|
||||||
public void testBoxUnboxInlineClassFromMethodReturnType() throws Exception {
|
public void testBoxUnboxInlineClassFromMethodReturnType() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxInlineClassFromMethodReturnType.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxInlineClassFromMethodReturnType.kt");
|
||||||
|
|||||||
+6
@@ -10431,6 +10431,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("emptyConstructorForInlineClass.kt")
|
||||||
public void testEmptyConstructorForInlineClass() throws Exception {
|
public void testEmptyConstructorForInlineClass() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/emptyConstructorForInlineClass.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/emptyConstructorForInlineClass.kt");
|
||||||
|
|||||||
+6
@@ -11415,6 +11415,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("emptyConstructorForInlineClass.kt")
|
||||||
public void testEmptyConstructorForInlineClass() throws Exception {
|
public void testEmptyConstructorForInlineClass() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/emptyConstructorForInlineClass.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/emptyConstructorForInlineClass.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user