Fix KotlinType of constructor call for inline classes

This commit is contained in:
Mikhail Zarechenskiy
2018-02-19 20:31:35 +03:00
parent 530dd01ca6
commit 413e2d7fa1
4 changed files with 59 additions and 13 deletions
@@ -2107,19 +2107,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
if (descriptor instanceof ConstructorDescriptor) {
if (InlineClassesUtilsKt.isInlineClass(descriptor.getContainingDeclaration())) {
KtValueArgument valueArgument = CollectionsKt.firstOrNull(expression.getValueArguments());
if (valueArgument == null) return null;
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 generateInlineClassConstructorCall(expression);
}
return generateNewCall(expression, resolvedCall);
@@ -2134,6 +2122,24 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
return invokeFunction(resolvedCall, receiver);
}
private StackValue generateInlineClassConstructorCall(@NotNull KtCallExpression expression) {
KtValueArgument valueArgument = CollectionsKt.singleOrNull(expression.getValueArguments());
assert valueArgument != null : "Inline class constructor call should have single argument";
KotlinType inlineClassType = kotlinType(expression);
assert inlineClassType != null && InlineClassesUtilsKt.isInlineClassType(inlineClassType) :
"Constructor call expression of inline class should have inline class type, but have: " + inlineClassType;
Type underlyingType = typeMapper.mapType(inlineClassType);
KotlinType underlyingKotlinType = InlineClassesUtilsKt.unsubstitutedUnderlyingType(inlineClassType);
StackValue argumentValue = gen(valueArgument.getArgumentExpression());
return StackValue.coercionValueForArgumentOfInlineClassConstructor(
argumentValue, underlyingType, inlineClassType, underlyingKotlinType
);
}
@Override
public StackValue visitCollectionLiteralExpression(
@NotNull KtCollectionLiteralExpression expression, StackValue data
@@ -4,20 +4,37 @@ inline class Result<T>(val a: Any?) {
fun typed(): T = a as T
}
fun <T> takeResult(r: Result<T>) {}
fun takeResultOfInt(r: Result<Int>) {}
fun takeInt(i: Int) {}
fun box(): String {
val asInt = Result<Int>(19)
val asString = Result<String>("sample")
val asResult = Result<Result<Int>>(asInt)
val asResultCtor = Result<Result<Int>>(Result<Int>(10))
takeResult(asInt)
takeResult(asString)
takeResult(asResult)
takeResult(asResultCtor)
takeResultOfInt(asInt)
takeInt(asInt.typed())
val unboxedInt = asInt.typed()
val unboxedString = asString.typed()
val unboxedResult = asResult.typed()
val unboxedAsCtor = asResultCtor.typed()
if (unboxedInt != 19) return "fail"
if (unboxedString != "sample") return "fail"
if (unboxedResult.typed() != 19) return "fail"
if (unboxedAsCtor.typed() != 10) return "fail"
if (asResult.typed().typed() != 19) return "fail"
if (asResultCtor.typed().typed() != 10) return "fail"
return "OK"
}
@@ -0,0 +1,17 @@
// !LANGUAGE: +InlineClasses
inline class Result<T>(val a: Any?)
fun test() {
val a = Result<Int>(1) // valueOf
val b = Result<String>("sample")
val c = Result<Result<Int>>(a) // box
val d = Result<Result<Int>>(Result<Int>(1)) // valueOf, box
}
// 2 INVOKESTATIC Result\$Erased.box
// 0 INVOKEVIRTUAL Result.unbox
// 2 valueOf
// 0 intValue
@@ -1959,6 +1959,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
doTest(fileName);
}
@TestMetadata("boxResultInlineClassOfConstructorCall.kt")
public void testBoxResultInlineClassOfConstructorCall() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/boxResultInlineClassOfConstructorCall.kt");
doTest(fileName);
}
@TestMetadata("boxThisOfInlineClass.kt")
public void testBoxThisOfInlineClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/boxThisOfInlineClass.kt");