Initial boxing for inline classes: local variable assignments
This commit is contained in:
@@ -3750,7 +3750,9 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
Type varType = getVariableTypeNoSharing(variableDescriptor);
|
||||
|
||||
StackValue storeTo = sharedVarType == null ? StackValue.local(index, varType) : StackValue.shared(index, varType);
|
||||
StackValue storeTo = sharedVarType == null ?
|
||||
StackValue.local(index, varType, variableDescriptor) :
|
||||
StackValue.shared(index, varType, variableDescriptor);
|
||||
|
||||
storeTo.putReceiver(v, false);
|
||||
if (variableDescriptor.isLateInit()) {
|
||||
@@ -3765,6 +3767,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
markLineNumber(variableDeclaration, false);
|
||||
Type resultType = initializer.type;
|
||||
KotlinType resultKotlinType = initializer.kotlinType;
|
||||
|
||||
if (isDelegatedLocalVariable(variableDescriptor)) {
|
||||
StackValue metadataValue = getVariableMetadataValue(variableDescriptor);
|
||||
@@ -3772,15 +3775,17 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
ResolvedCall<FunctionDescriptor> provideDelegateCall = bindingContext.get(PROVIDE_DELEGATE_RESOLVED_CALL, variableDescriptor);
|
||||
if (provideDelegateCall != null) {
|
||||
resultType = generateProvideDelegateCallForLocalVariable(initializer, metadataValue, provideDelegateCall);
|
||||
StackValue provideDelegateValue = generateProvideDelegateCallForLocalVariable(initializer, metadataValue, provideDelegateCall);
|
||||
resultType = provideDelegateValue.type;
|
||||
resultKotlinType = provideDelegateValue.kotlinType;
|
||||
}
|
||||
}
|
||||
|
||||
storeTo.storeSelector(resultType, null, v);
|
||||
storeTo.storeSelector(resultType, resultKotlinType, v);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Type generateProvideDelegateCallForLocalVariable(
|
||||
private StackValue generateProvideDelegateCallForLocalVariable(
|
||||
@NotNull StackValue initializer,
|
||||
StackValue metadataValue,
|
||||
ResolvedCall<FunctionDescriptor> provideDelegateResolvedCall
|
||||
@@ -3808,7 +3813,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
result.put(result.type, result.kotlinType, v);
|
||||
tempVariables.remove(arguments.get(0).asElement());
|
||||
tempVariables.remove(arguments.get(1).asElement());
|
||||
return result.type;
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -23,9 +23,7 @@ import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.KtExpression;
|
||||
import org.jetbrains.kotlin.psi.ValueArgument;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor;
|
||||
import org.jetbrains.kotlin.resolve.*;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
|
||||
@@ -153,7 +151,7 @@ public abstract class StackValue {
|
||||
|
||||
@NotNull
|
||||
public static Local local(int index, @NotNull Type type, @NotNull VariableDescriptor descriptor) {
|
||||
return new Local(index, type, descriptor.isLateInit(), descriptor.getName());
|
||||
return new Local(index, type, descriptor.getType(), descriptor.isLateInit(), descriptor.getName());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -174,7 +172,7 @@ public abstract class StackValue {
|
||||
|
||||
@NotNull
|
||||
public static StackValue shared(int index, @NotNull Type type, @NotNull VariableDescriptor descriptor) {
|
||||
return new Shared(index, type, descriptor.isLateInit(), descriptor.getName());
|
||||
return new Shared(index, type, descriptor.getType(), descriptor.isLateInit(), descriptor.getName());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -363,12 +361,81 @@ public abstract class StackValue {
|
||||
v.invokevirtual(methodOwner.getInternalName(), type.getClassName() + "Value", "()" + type.getDescriptor(), false);
|
||||
}
|
||||
|
||||
private static void boxInlineClass(@NotNull KotlinType kotlinType, @NotNull InstructionAdapter v) {
|
||||
Type boxedType = KotlinTypeMapper.mapInlineClassTypeAsDeclaration(kotlinType);
|
||||
Type owner = KotlinTypeMapper.mapToErasedInlineClassType(kotlinType);
|
||||
Type underlyingType = KotlinTypeMapper.mapUnderlyingTypeOfInlineClassType(kotlinType);
|
||||
v.invokestatic(
|
||||
owner.getInternalName(),
|
||||
InlineClassDescriptorResolver.BOX_METHOD_NAME.asString(),
|
||||
Type.getMethodDescriptor(boxedType, underlyingType),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
private static void unboxInlineClass(@NotNull KotlinType kotlinType, @NotNull InstructionAdapter v) {
|
||||
Type owner = KotlinTypeMapper.mapInlineClassTypeAsDeclaration(kotlinType);
|
||||
Type resultType = KotlinTypeMapper.mapUnderlyingTypeOfInlineClassType(kotlinType);
|
||||
v.invokevirtual(
|
||||
owner.getInternalName(),
|
||||
InlineClassDescriptorResolver.UNBOX_METHOD_NAME.asString(),
|
||||
"()" + resultType.getDescriptor(),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
protected void coerceTo(@NotNull Type toType, @Nullable KotlinType toKotlinType, @NotNull InstructionAdapter v) {
|
||||
coerce(this.type, toType, v);
|
||||
coerce(this.type, this.kotlinType, toType, toKotlinType, v);
|
||||
}
|
||||
|
||||
protected void coerceFrom(@NotNull Type topOfStackType, @Nullable KotlinType topOfStackKotlinType, @NotNull InstructionAdapter v) {
|
||||
coerce(topOfStackType, this.type, v);
|
||||
coerce(topOfStackType, topOfStackKotlinType, this.type, this.kotlinType, v);
|
||||
}
|
||||
|
||||
public static void coerce(
|
||||
@NotNull Type fromType,
|
||||
@Nullable KotlinType fromKotlinType,
|
||||
@NotNull Type toType,
|
||||
@Nullable KotlinType toKotlinType,
|
||||
@NotNull InstructionAdapter v
|
||||
) {
|
||||
if (coerceInlineClasses(fromType, fromKotlinType, toType, toKotlinType, v)) return;
|
||||
coerce(fromType, toType, v);
|
||||
}
|
||||
|
||||
private static boolean coerceInlineClasses(
|
||||
@NotNull Type fromType,
|
||||
@Nullable KotlinType fromKotlinType,
|
||||
@NotNull Type toType,
|
||||
@Nullable KotlinType toKotlinType,
|
||||
@NotNull InstructionAdapter v
|
||||
) {
|
||||
if (fromKotlinType == null || toKotlinType == null) return false;
|
||||
if (!InlineClassesUtilsKt.isInlineClassType(fromKotlinType)) return false;
|
||||
|
||||
if (fromKotlinType.equals(toKotlinType) && fromType.equals(toType)) return true;
|
||||
|
||||
boolean isFromTypeUnboxed = isUnboxedInlineClass(fromKotlinType, fromType);
|
||||
if (InlineClassesUtilsKt.isInlineClassType(toKotlinType)) {
|
||||
boolean isToTypeUnboxed = isUnboxedInlineClass(toKotlinType, toType);
|
||||
if (isFromTypeUnboxed && !isToTypeUnboxed) {
|
||||
boxInlineClass(fromKotlinType, v);
|
||||
}
|
||||
else if (!isFromTypeUnboxed) {
|
||||
unboxInlineClass(fromKotlinType, v);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (isFromTypeUnboxed) {
|
||||
boxInlineClass(fromKotlinType, v);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isUnboxedInlineClass(@NotNull KotlinType kotlinType, @NotNull Type actualType) {
|
||||
return KotlinTypeMapper.mapUnderlyingTypeOfInlineClassType(kotlinType).equals(actualType);
|
||||
}
|
||||
|
||||
public static void coerce(@NotNull Type fromType, @NotNull Type toType, @NotNull InstructionAdapter v) {
|
||||
@@ -674,8 +741,8 @@ public abstract class StackValue {
|
||||
private final boolean isLateinit;
|
||||
private final Name name;
|
||||
|
||||
private Local(int index, Type type, boolean isLateinit, Name name) {
|
||||
super(type, false);
|
||||
private Local(int index, Type type, KotlinType kotlinType, boolean isLateinit, Name name) {
|
||||
super(type, kotlinType, false);
|
||||
|
||||
if (index < 0) {
|
||||
throw new IllegalStateException("local variable index must be non-negative");
|
||||
@@ -691,7 +758,7 @@ public abstract class StackValue {
|
||||
}
|
||||
|
||||
private Local(int index, Type type) {
|
||||
this(index, type, false, null);
|
||||
this(index, type, null, false, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -876,7 +943,7 @@ public abstract class StackValue {
|
||||
private final Type type;
|
||||
|
||||
public ArrayElement(Type type, StackValue array, StackValue index) {
|
||||
super(type, false, false, new Receiver(Type.LONG_TYPE, array, index), true);
|
||||
super(type, null, false, false, new Receiver(Type.LONG_TYPE, array, index), true);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@@ -1069,7 +1136,7 @@ public abstract class StackValue {
|
||||
@Nullable ResolvedCall<FunctionDescriptor> resolvedSetCall,
|
||||
@NotNull ExpressionCodegen codegen
|
||||
) {
|
||||
super(type, false, false, collectionElementReceiver, true);
|
||||
super(type, null, false, false, collectionElementReceiver, true);
|
||||
this.resolvedGetCall = resolvedGetCall;
|
||||
this.resolvedSetCall = resolvedSetCall;
|
||||
this.setter = resolvedSetCall == null ? null :
|
||||
@@ -1193,7 +1260,7 @@ public abstract class StackValue {
|
||||
@NotNull StackValue receiver,
|
||||
@Nullable DeclarationDescriptor descriptor
|
||||
) {
|
||||
super(type, isStatic, isStatic, receiver, receiver.canHaveSideEffects());
|
||||
super(type, null, isStatic, isStatic, receiver, receiver.canHaveSideEffects());
|
||||
this.owner = owner;
|
||||
this.name = name;
|
||||
this.descriptor = descriptor;
|
||||
@@ -1233,7 +1300,7 @@ public abstract class StackValue {
|
||||
@NotNull StackValue receiver, @NotNull ExpressionCodegen codegen, @Nullable ResolvedCall resolvedCall,
|
||||
boolean skipLateinitAssertion
|
||||
) {
|
||||
super(type, isStatic(isStaticBackingField, getter), isStatic(isStaticBackingField, setter), receiver, true);
|
||||
super(type, descriptor.getType(), isStatic(isStaticBackingField, getter), isStatic(isStaticBackingField, setter), receiver, true);
|
||||
this.backingFieldOwner = backingFieldOwner;
|
||||
this.getter = getter;
|
||||
this.setter = setter;
|
||||
@@ -1419,8 +1486,8 @@ public abstract class StackValue {
|
||||
private final boolean isLateinit;
|
||||
private final Name name;
|
||||
|
||||
public Shared(int index, Type type, boolean isLateinit, Name name) {
|
||||
super(type, false, false, local(index, OBJECT_TYPE), false);
|
||||
public Shared(int index, Type type, KotlinType kotlinType, boolean isLateinit, Name name) {
|
||||
super(type, kotlinType, false, false, local(index, OBJECT_TYPE), false);
|
||||
this.index = index;
|
||||
|
||||
if (isLateinit && name == null) {
|
||||
@@ -1432,7 +1499,7 @@ public abstract class StackValue {
|
||||
}
|
||||
|
||||
public Shared(int index, Type type) {
|
||||
this(index, type, false, null);
|
||||
this(index, type, null, false, null);
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
@@ -1491,7 +1558,7 @@ public abstract class StackValue {
|
||||
Type type, Type owner, String name, StackValue.Field receiver,
|
||||
boolean isLateinit, Name variableName
|
||||
) {
|
||||
super(type, false, false, receiver, receiver.canHaveSideEffects());
|
||||
super(type, null, false, false, receiver, receiver.canHaveSideEffects());
|
||||
|
||||
if (isLateinit && variableName == null) {
|
||||
throw new IllegalArgumentException("variableName should be non-null for captured lateinit variable " + name);
|
||||
@@ -1631,12 +1698,13 @@ public abstract class StackValue {
|
||||
|
||||
public StackValueWithSimpleReceiver(
|
||||
@NotNull Type type,
|
||||
@Nullable KotlinType kotlinType,
|
||||
boolean isStaticPut,
|
||||
boolean isStaticStore,
|
||||
@NotNull StackValue receiver,
|
||||
boolean canHaveSideEffects
|
||||
) {
|
||||
super(type, canHaveSideEffects);
|
||||
super(type, kotlinType, canHaveSideEffects);
|
||||
this.receiver = receiver;
|
||||
this.isStaticPut = isStaticPut;
|
||||
this.isStaticStore = isStaticStore;
|
||||
@@ -1783,7 +1851,7 @@ public abstract class StackValue {
|
||||
@NotNull StackValueWithSimpleReceiver originalValue,
|
||||
@NotNull ComplexReceiver receiver
|
||||
) {
|
||||
super(type, bothReceiverStatic(originalValue), bothReceiverStatic(originalValue), receiver, originalValue.canHaveSideEffects());
|
||||
super(type, null, bothReceiverStatic(originalValue), bothReceiverStatic(originalValue), receiver, originalValue.canHaveSideEffects());
|
||||
this.originalValue = originalValue;
|
||||
}
|
||||
|
||||
@@ -1868,7 +1936,7 @@ public abstract class StackValue {
|
||||
@Nullable private final Label ifNull;
|
||||
|
||||
public SafeFallback(@NotNull Type type, @Nullable Label ifNull, StackValue receiver) {
|
||||
super(type, false, false, receiver, true);
|
||||
super(type, null, false, false, receiver, true);
|
||||
this.ifNull = ifNull;
|
||||
}
|
||||
|
||||
|
||||
@@ -470,11 +470,33 @@ public class KotlinTypeMapper {
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Type mapInlineClassTypeAsDeclaration(@NotNull KotlinType kotlinType) {
|
||||
return mapInlineClassType(kotlinType, TypeMappingMode.CLASS_DECLARATION);
|
||||
}
|
||||
|
||||
public static Type mapInlineClassType(
|
||||
@NotNull
|
||||
public static Type mapUnderlyingTypeOfInlineClassType(@NotNull KotlinType kotlinType) {
|
||||
KotlinType underlyingType = InlineClassesUtilsKt.underlyingTypeOfInlineClassType(kotlinType);
|
||||
if (underlyingType == null) {
|
||||
throw new IllegalStateException("There should be underlying type for inline class type: " + kotlinType);
|
||||
}
|
||||
return mapInlineClassType(underlyingType, TypeMappingMode.DEFAULT);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Type mapToErasedInlineClassType(@NotNull KotlinType kotlinType) {
|
||||
return Type.getObjectType(
|
||||
mapInlineClassTypeAsDeclaration(kotlinType).getInternalName() + JvmAbi.ERASED_INLINE_CLASS_SUFFIX
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Type mapInlineClassType(@NotNull KotlinType kotlinType) {
|
||||
return mapInlineClassType(kotlinType, TypeMappingMode.DEFAULT);
|
||||
}
|
||||
|
||||
private static Type mapInlineClassType(
|
||||
@NotNull KotlinType kotlinType,
|
||||
@NotNull TypeMappingMode mode
|
||||
) {
|
||||
|
||||
Reference in New Issue
Block a user