Propagate KotlinType into create method for coroutines

#KT-27526 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2018-10-11 17:25:59 +03:00
parent a8abd8cceb
commit 0201694f84
15 changed files with 264 additions and 28 deletions
@@ -638,10 +638,18 @@ public class AsmUtil {
) {
assert !info.isStatic();
Type fieldType = info.getFieldType();
KotlinType fieldKotlinType = info.getFieldKotlinType();
KotlinType nullableAny;
if (fieldKotlinType != null) {
nullableAny = fieldKotlinType.getConstructor().getBuiltIns().getNullableAnyType();
} else {
nullableAny = null;
}
iv.load(ownerIndex, info.getOwnerType());//this
if (cast) {
iv.load(index, AsmTypes.OBJECT_TYPE); //param
StackValue.coerce(AsmTypes.OBJECT_TYPE, fieldType, iv);
StackValue.coerce(AsmTypes.OBJECT_TYPE, nullableAny, fieldType, fieldKotlinType, iv);
} else {
iv.load(index, fieldType); //param
}
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
import org.jetbrains.kotlin.serialization.DescriptorSerializer;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.SimpleType;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils;
import org.jetbrains.kotlin.util.OperatorNameConventions;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
@@ -490,13 +491,14 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
List<FieldInfo> args = Lists.newArrayList();
ClassDescriptor captureThis = closure.getCapturedOuterClassDescriptor();
if (captureThis != null) {
Type type = typeMapper.mapType(captureThis);
args.add(FieldInfo.createForHiddenField(ownerType, type, CAPTURED_THIS_FIELD));
SimpleType thisType = captureThis.getDefaultType();
Type type = typeMapper.mapType(thisType);
args.add(FieldInfo.createForHiddenField(ownerType, type, thisType, CAPTURED_THIS_FIELD));
}
KotlinType captureReceiverType = closure.getCapturedReceiverFromOuterContext();
if (captureReceiverType != null) {
String fieldName = closure.getCapturedReceiverFieldName(typeMapper.getBindingContext(), languageVersionSettings);
args.add(FieldInfo.createForHiddenField(ownerType, typeMapper.mapType(captureReceiverType), fieldName));
args.add(FieldInfo.createForHiddenField(ownerType, typeMapper.mapType(captureReceiverType), captureReceiverType, fieldName));
}
for (EnclosedValueDescriptor enclosedValueDescriptor : closure.getCaptureVariables().values()) {
@@ -505,7 +507,10 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
ExpressionTypingUtils.isLocalFunction(descriptor)) {
args.add(
FieldInfo.createForHiddenField(
ownerType, enclosedValueDescriptor.getType(), enclosedValueDescriptor.getFieldName()
ownerType,
enclosedValueDescriptor.getType(),
enclosedValueDescriptor.getKotlinType(),
enclosedValueDescriptor.getFieldName()
)
);
}
@@ -6,11 +6,13 @@
package org.jetbrains.kotlin.codegen;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.CompanionObjectMapping;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.org.objectweb.asm.Type;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isNonCompanionObject;
@@ -29,7 +31,9 @@ public class FieldInfo {
ClassDescriptor ownerDescriptor = DescriptorUtils.getParentOfType(classDescriptor, ClassDescriptor.class);
assert ownerDescriptor != null : "Owner not found for class: " + classDescriptor;
Type ownerType = typeMapper.mapClass(ownerDescriptor);
return new FieldInfo(ownerType, typeMapper.mapType(classDescriptor), classDescriptor.getName().asString(), true);
KotlinType fieldKotlinType = classDescriptor.getDefaultType();
Type fieldType = typeMapper.mapType(fieldKotlinType);
return new FieldInfo(ownerType, fieldType, fieldKotlinType, classDescriptor.getName().asString(), true);
}
@NotNull
@@ -38,23 +42,43 @@ public class FieldInfo {
@NotNull KotlinTypeMapper typeMapper,
@NotNull String name
) {
Type type = typeMapper.mapType(classDescriptor);
return new FieldInfo(type, type, name, true);
Type owner = typeMapper.mapClass(classDescriptor);
KotlinType fieldKotlinType = classDescriptor.getDefaultType();
Type fieldType = typeMapper.mapType(fieldKotlinType);
return new FieldInfo(owner, fieldType, fieldKotlinType, name, true);
}
@NotNull
public static FieldInfo createForHiddenField(@NotNull Type owner, @NotNull Type fieldType, @NotNull String fieldName) {
return new FieldInfo(owner, fieldType, fieldName, false);
return createForHiddenField(owner, fieldType, null, fieldName);
}
@NotNull
public static FieldInfo createForHiddenField(
@NotNull Type owner,
@NotNull Type fieldType,
@Nullable KotlinType fieldKotlinType,
@NotNull String fieldName
) {
return new FieldInfo(owner, fieldType, fieldKotlinType, fieldName, false);
}
private final Type fieldType;
private final KotlinType fieldKotlinType;
private final Type ownerType;
private final String fieldName;
private final boolean isStatic;
private FieldInfo(@NotNull Type ownerType, @NotNull Type fieldType, @NotNull String fieldName, boolean isStatic) {
private FieldInfo(
@NotNull Type ownerType,
@NotNull Type fieldType,
@Nullable KotlinType fieldKotlinType,
@NotNull String fieldName,
boolean isStatic
) {
this.ownerType = ownerType;
this.fieldType = fieldType;
this.fieldKotlinType = fieldKotlinType;
this.fieldName = fieldName;
this.isStatic = isStatic;
}
@@ -64,6 +88,11 @@ public class FieldInfo {
return fieldType;
}
@Nullable
public KotlinType getFieldKotlinType() {
return fieldKotlinType;
}
@NotNull
public Type getOwnerType() {
return ownerType;
@@ -340,7 +340,19 @@ public abstract class StackValue {
@NotNull
public static Field field(@NotNull Type type, @NotNull Type owner, @NotNull String name, boolean isStatic, @NotNull StackValue receiver) {
return field(type, null, owner, name, isStatic, receiver, null);
return field(type, null, owner, name, isStatic, receiver);
}
@NotNull
public static Field field(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull Type owner,
@NotNull String name,
boolean isStatic,
@NotNull StackValue receiver
) {
return field(type, kotlinType, owner, name, isStatic, receiver, null);
}
@NotNull
@@ -363,7 +375,14 @@ public abstract class StackValue {
@NotNull
public static Field field(@NotNull FieldInfo info, @NotNull StackValue receiver) {
return field(info.getFieldType(), Type.getObjectType(info.getOwnerInternalName()), info.getFieldName(), info.isStatic(), receiver);
return field(
info.getFieldType(),
info.getFieldKotlinType(),
Type.getObjectType(info.getOwnerInternalName()),
info.getFieldName(),
info.isStatic(),
receiver
);
}
@NotNull
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.ExpressionCodegen;
import org.jetbrains.kotlin.codegen.StackValue;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.org.objectweb.asm.Type;
public final class EnclosedValueDescriptor {
@@ -29,18 +30,21 @@ public final class EnclosedValueDescriptor {
private final StackValue.StackValueWithSimpleReceiver innerValue;
private final StackValue instanceValue;
private final Type type;
private final KotlinType kotlinType;
public EnclosedValueDescriptor(
@NotNull String fieldName,
@Nullable DeclarationDescriptor descriptor,
@NotNull StackValue.StackValueWithSimpleReceiver innerValue,
@NotNull Type type
@NotNull Type type,
@Nullable KotlinType kotlinType
) {
this.fieldName = fieldName;
this.descriptor = descriptor;
this.innerValue = innerValue;
this.instanceValue = innerValue;
this.type = type;
this.kotlinType = kotlinType;
}
public EnclosedValueDescriptor(
@@ -48,13 +52,15 @@ public final class EnclosedValueDescriptor {
@Nullable DeclarationDescriptor descriptor,
@NotNull StackValue.StackValueWithSimpleReceiver innerValue,
@NotNull StackValue.Field instanceValue,
@NotNull Type type
@NotNull Type type,
@Nullable KotlinType kotlinType
) {
this.fieldName = name;
this.descriptor = descriptor;
this.innerValue = innerValue;
this.instanceValue = instanceValue;
this.type = type;
this.kotlinType = kotlinType;
}
@NotNull
@@ -82,6 +88,11 @@ public final class EnclosedValueDescriptor {
return type;
}
@Nullable
public KotlinType getKotlinType() {
return kotlinType;
}
@Override
public String toString() {
return fieldName + " " + type + " -> " + descriptor;
@@ -63,11 +63,11 @@ public interface LocalLookup {
if (sharedVarType != null) {
StackValue.Field wrapperValue = StackValue.receiverWithRefWrapper(localType, classType, fieldName, thiz, vd);
innerValue = StackValue.fieldForSharedVar(localType, classType, fieldName, wrapperValue, vd);
enclosedValueDescriptor = new EnclosedValueDescriptor(fieldName, d, innerValue, wrapperValue, type);
enclosedValueDescriptor = new EnclosedValueDescriptor(fieldName, d, innerValue, wrapperValue, type, kotlinType);
}
else {
innerValue = StackValue.field(type, kotlinType, classType, fieldName, false, thiz, vd);
enclosedValueDescriptor = new EnclosedValueDescriptor(fieldName, d, innerValue, type);
enclosedValueDescriptor = new EnclosedValueDescriptor(fieldName, d, innerValue, type, kotlinType);
}
closure.captureVariable(enclosedValueDescriptor);
@@ -118,7 +118,7 @@ public interface LocalLookup {
localType, null, classType, fieldName, false, StackValue.LOCAL_0, vd
);
closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, localType));
closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, localType, null));
return innerValue;
}
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.org.objectweb.asm.Label;
import org.jetbrains.org.objectweb.asm.Type;
@@ -64,8 +65,9 @@ public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
public StackValue getReceiverExpression(KotlinTypeMapper typeMapper) {
assert getCallableDescriptorWithReceiver() != null;
@SuppressWarnings("ConstantConditions")
Type asmType = typeMapper.mapType(getCallableDescriptorWithReceiver().getExtensionReceiverParameter().getType());
return StackValue.local(AsmUtil.getReceiverIndex(this, getContextDescriptor()), asmType);
KotlinType kotlinType = getCallableDescriptorWithReceiver().getExtensionReceiverParameter().getType();
Type asmType = typeMapper.mapType(kotlinType);
return StackValue.local(AsmUtil.getReceiverIndex(this, getContextDescriptor()), asmType, kotlinType);
}
@Override
@@ -347,7 +347,7 @@ class CoroutineCodegenForLambda private constructor(
// pass captured closure to constructor
val constructorParameters = calculateConstructorParameters(typeMapper, languageVersionSettings, closure, owner)
for (parameter in constructorParameters) {
StackValue.field(parameter, thisInstance).put(parameter.fieldType, this)
StackValue.field(parameter, thisInstance).put(parameter.fieldType, parameter.fieldKotlinType, this)
}
// load resultContinuation
@@ -377,7 +377,11 @@ class CoroutineCodegenForLambda private constructor(
load(1, AsmTypes.OBJECT_TYPE)
iconst(index - 1)
aload(AsmTypes.OBJECT_TYPE)
StackValue.coerce(AsmTypes.OBJECT_TYPE, fieldInfoForCoroutineLambdaParameter.fieldType, this)
StackValue.coerce(
AsmTypes.OBJECT_TYPE, builtIns.nullableAnyType,
fieldInfoForCoroutineLambdaParameter.fieldType, fieldInfoForCoroutineLambdaParameter.fieldKotlinType,
this
)
putfield(
fieldInfoForCoroutineLambdaParameter.ownerInternalName,
fieldInfoForCoroutineLambdaParameter.fieldName,
@@ -386,7 +390,11 @@ class CoroutineCodegenForLambda private constructor(
} else {
if (generateErasedCreate) {
load(index, AsmTypes.OBJECT_TYPE)
StackValue.coerce(AsmTypes.OBJECT_TYPE, fieldInfoForCoroutineLambdaParameter.fieldType, this)
StackValue.coerce(
AsmTypes.OBJECT_TYPE, builtIns.nullableAnyType,
fieldInfoForCoroutineLambdaParameter.fieldType, fieldInfoForCoroutineLambdaParameter.fieldKotlinType,
this
)
} else {
load(index, fieldInfoForCoroutineLambdaParameter.fieldType)
}
@@ -434,6 +442,7 @@ class CoroutineCodegenForLambda private constructor(
FieldInfo.createForHiddenField(
typeMapper.mapClass(closureContext.thisDescriptor),
typeMapper.mapType(type),
type,
name
)
@@ -255,25 +255,27 @@ class PsiExpressionLambda(
arrayListOf<CapturedParamDesc>().apply {
val captureThis = closure.capturedOuterClassDescriptor
if (captureThis != null) {
val type = typeMapper.mapType(captureThis)
val kotlinType = captureThis.defaultType
val type = typeMapper.mapType(kotlinType)
val descriptor = EnclosedValueDescriptor(
AsmUtil.CAPTURED_THIS_FIELD, null,
StackValue.field(type, lambdaClassType, AsmUtil.CAPTURED_THIS_FIELD, false, StackValue.LOCAL_0),
type
type, kotlinType
)
add(getCapturedParamInfo(descriptor))
}
if (closure.capturedReceiverFromOuterContext != null) {
val type = typeMapper.mapType(closure.capturedReceiverFromOuterContext!!).let {
val capturedReceiver = closure.capturedReceiverFromOuterContext
if (capturedReceiver != null) {
val type = typeMapper.mapType(capturedReceiver).let {
if (isBoundCallableReference) it.boxReceiverForBoundReference() else it
}
val fieldName = closure.getCapturedReceiverFieldName(typeMapper.bindingContext, languageVersionSettings)
val descriptor = EnclosedValueDescriptor(
fieldName, null,
StackValue.field(type, lambdaClassType, fieldName, false, StackValue.LOCAL_0),
type
StackValue.field(type, capturedReceiver, lambdaClassType, fieldName, false, StackValue.LOCAL_0),
type, capturedReceiver
)
add(getCapturedParamInfo(descriptor))
}
@@ -0,0 +1,126 @@
// WITH_COROUTINES
// WITH_RUNTIME
// IGNORE_BACKEND: JVM_IR, JS_IR
import helpers.*
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
inline class BoxAny(val value: Any?) {
val intValue: Int get() = value as Int
}
inline class BoxInt(val value: Int)
inline class BoxLong(val value: Long)
class EmptyContinuation<T> : Continuation<T> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resumeWith(result: Result<T>) {}
}
suspend fun foo(block: suspend (BoxAny) -> Unit) {
block(BoxAny(1))
block.startCoroutineUninterceptedOrReturn(BoxAny(1), EmptyContinuation())
}
suspend fun fooReceiver(block: suspend BoxAny.() -> Unit) {
BoxAny(1).block()
block.startCoroutineUninterceptedOrReturn(BoxAny(1), EmptyContinuation())
}
suspend fun bar(block: suspend (BoxInt) -> Unit) {
block(BoxInt(2))
block.startCoroutineUninterceptedOrReturn(BoxInt(2), EmptyContinuation())
}
suspend fun barReceiver(block: suspend BoxInt.() -> Unit) {
BoxInt(2).block()
block.startCoroutineUninterceptedOrReturn(BoxInt(2), EmptyContinuation())
}
suspend fun baz(block: suspend (BoxLong) -> Unit) {
block(BoxLong(3))
block.startCoroutineUninterceptedOrReturn(BoxLong(3), EmptyContinuation())
}
suspend fun bazReceiver(block: suspend BoxLong.() -> Unit) {
BoxLong(3).block()
block.startCoroutineUninterceptedOrReturn(BoxLong(3), EmptyContinuation())
}
suspend fun BoxAny.extension(block: suspend BoxAny.() -> Unit) {
this.block()
block()
block.startCoroutineUninterceptedOrReturn(this, EmptyContinuation())
}
suspend fun BoxInt.extension(block: suspend BoxInt.() -> Unit) {
this.block()
block()
block.startCoroutineUninterceptedOrReturn(this, EmptyContinuation())
}
suspend fun BoxLong.extension(block: suspend BoxLong.() -> Unit) {
this.block()
block()
block.startCoroutineUninterceptedOrReturn(this, EmptyContinuation())
}
fun runBlocking(block: suspend () -> Unit) {
block.startCoroutine(object : Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resumeWith(result: Result<Unit>) {
(block as Function1<Continuation<Unit>, Any?>)(this)
}
})
}
fun box(): String {
var result = 0
runBlocking {
foo { boxAny ->
result += boxAny.intValue
}
fooReceiver {
result += this.intValue
}
bar { boxInt ->
result += boxInt.value
}
barReceiver {
result += value
}
baz { boxLong ->
result += boxLong.value.toInt()
}
bazReceiver {
result += this.value.toInt()
}
val b = BoxAny(4)
b.extension {
result += intValue
}
val bInt = BoxInt(5)
BoxInt(5).extension {
result += value + bInt.value
}
BoxLong(6).extension {
result += value.toInt()
}
}
return if (result == 168) "OK" else "Error: $result"
}
@@ -11974,6 +11974,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/inlineClasses/unboxNullableValueOfInlineClassWithPrimitiveUnderlyingType.kt");
}
@TestMetadata("unboxParameterOfSuspendLambdaBeforeInvoke.kt")
public void testUnboxParameterOfSuspendLambdaBeforeInvoke() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/unboxParameterOfSuspendLambdaBeforeInvoke.kt");
}
@TestMetadata("unboxReceiverOnCallingMethodFromInlineClass.kt")
public void testUnboxReceiverOnCallingMethodFromInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/unboxReceiverOnCallingMethodFromInlineClass.kt");
@@ -11974,6 +11974,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/inlineClasses/unboxNullableValueOfInlineClassWithPrimitiveUnderlyingType.kt");
}
@TestMetadata("unboxParameterOfSuspendLambdaBeforeInvoke.kt")
public void testUnboxParameterOfSuspendLambdaBeforeInvoke() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/unboxParameterOfSuspendLambdaBeforeInvoke.kt");
}
@TestMetadata("unboxReceiverOnCallingMethodFromInlineClass.kt")
public void testUnboxReceiverOnCallingMethodFromInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/unboxReceiverOnCallingMethodFromInlineClass.kt");
@@ -11979,6 +11979,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/inlineClasses/unboxNullableValueOfInlineClassWithPrimitiveUnderlyingType.kt");
}
@TestMetadata("unboxParameterOfSuspendLambdaBeforeInvoke.kt")
public void testUnboxParameterOfSuspendLambdaBeforeInvoke() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/unboxParameterOfSuspendLambdaBeforeInvoke.kt");
}
@TestMetadata("unboxReceiverOnCallingMethodFromInlineClass.kt")
public void testUnboxReceiverOnCallingMethodFromInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/unboxReceiverOnCallingMethodFromInlineClass.kt");
@@ -10509,6 +10509,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/inlineClasses/unboxNullableValueOfInlineClassWithPrimitiveUnderlyingType.kt");
}
@TestMetadata("unboxParameterOfSuspendLambdaBeforeInvoke.kt")
public void testUnboxParameterOfSuspendLambdaBeforeInvoke() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/unboxParameterOfSuspendLambdaBeforeInvoke.kt");
}
@TestMetadata("unboxReceiverOnCallingMethodFromInlineClass.kt")
public void testUnboxReceiverOnCallingMethodFromInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/unboxReceiverOnCallingMethodFromInlineClass.kt");
@@ -11554,6 +11554,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/inlineClasses/unboxNullableValueOfInlineClassWithPrimitiveUnderlyingType.kt");
}
@TestMetadata("unboxParameterOfSuspendLambdaBeforeInvoke.kt")
public void testUnboxParameterOfSuspendLambdaBeforeInvoke() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/unboxParameterOfSuspendLambdaBeforeInvoke.kt");
}
@TestMetadata("unboxReceiverOnCallingMethodFromInlineClass.kt")
public void testUnboxReceiverOnCallingMethodFromInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/unboxReceiverOnCallingMethodFromInlineClass.kt");