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:
Mikhail Zarechenskiy
2018-02-09 04:10:58 +03:00
parent 6320368609
commit 8015295059
10 changed files with 123 additions and 10 deletions
@@ -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)
}