Use non-local return target instead of inline site in suspend function

return type coercion.
 #KT-43226 Fixed
This commit is contained in:
Ilmir Usmanov
2020-11-09 21:19:18 +01:00
parent d4f08018ce
commit fa42a6ba58
12 changed files with 165 additions and 33 deletions
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.config.ApiVersion;
import org.jetbrains.kotlin.config.JVMAssertionsMode;
import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
@@ -1705,26 +1706,38 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
Type returnType;
KotlinType returnKotlinType;
if (isNonLocalReturn) {
// This is inline lambda. Find inline-site and check, whether it is suspend functions returning unboxed inline class
CodegenContext<?> inlineSiteContext = this.context.getFirstCrossInlineOrNonInlineContext();
KotlinType originalInlineClass = null;
boolean invokeSuspendOfLambda = false;
FunctionDescriptor inlineSiteDescriptor = null;
if (inlineSiteContext instanceof MethodContext) {
inlineSiteDescriptor = ((MethodContext) inlineSiteContext).getFunctionDescriptor();
originalInlineClass = CoroutineCodegenUtilKt
.originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass(inlineSiteDescriptor, typeMapper);
invokeSuspendOfLambda = CoroutineCodegenUtilKt.isInvokeSuspendOfLambda(inlineSiteDescriptor);
}
if (originalInlineClass != null) {
returnType = typeMapper.mapType(originalInlineClass);
returnKotlinType = originalInlineClass;
} else if (!invokeSuspendOfLambda) {
returnType = nonLocalReturn.returnType.getType();
returnKotlinType = nonLocalReturn.returnType.getKotlinType();
} else {
FunctionDescriptor returnTarget =
nonLocalReturn.descriptor instanceof FunctionDescriptor
? (FunctionDescriptor) nonLocalReturn.descriptor
: null;
if (returnTarget == null || !returnTarget.isSuspend()) {
JvmKotlinType jvmKotlinType = nonLocalReturn.getJvmKotlinType(typeMapper);
returnType = jvmKotlinType.getType();
returnKotlinType = jvmKotlinType.getKotlinType();
} else if (returnTarget instanceof AnonymousFunctionDescriptor) {
// Suspend lambdas always return Any?
returnType = OBJECT_TYPE;
returnKotlinType = inlineSiteDescriptor.getReturnType();
returnKotlinType = state.getModule().getBuiltIns().getNullableAnyType();
} else {
// This is inline lambda, but return target is ordinary, yet suspend, function.
// Find inline-site and check, whether it is suspend functions returning unboxed inline class
CodegenContext<?> inlineSiteContext = this.context.getFirstCrossInlineOrNonInlineContext();
KotlinType originalInlineClass = null;
if (inlineSiteContext instanceof MethodContext) {
FunctionDescriptor view = CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(returnTarget, state);
originalInlineClass =
CoroutineCodegenUtilKt.originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass(view, typeMapper);
}
if (originalInlineClass != null) {
// As an optimization, suspend functions, returning inline classes with reference underlying
// type return unboxed inline class. Save the type so the coercer will not box it.
returnType = typeMapper.mapType(originalInlineClass);
returnKotlinType = originalInlineClass;
} else {
JvmKotlinType jvmKotlinType = nonLocalReturn.getJvmKotlinType(typeMapper);
returnType = jvmKotlinType.getType();
returnKotlinType = jvmKotlinType.getKotlinType();
}
}
}
else {
@@ -1788,13 +1801,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
FunctionDescriptor containingFunction =
BindingContextUtils.getContainingFunctionSkipFunctionLiterals(descriptor, true).getFirst();
//FIRST_FUN_LABEL to prevent clashing with existing labels
return new NonLocalReturnInfo(
new JvmKotlinType(
typeMapper.mapReturnType(containingFunction),
containingFunction.getReturnType()
),
FIRST_FUN_LABEL
);
return new NonLocalReturnInfo(containingFunction, FIRST_FUN_LABEL);
} else {
//local
return null;
@@ -1807,10 +1814,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
assert element != null : "Expression should be not null " + expression.getText();
assert elementDescriptor != null : "Descriptor should be not null: " + element.getText();
CallableDescriptor function = (CallableDescriptor) elementDescriptor;
return new NonLocalReturnInfo(
new JvmKotlinType(typeMapper.mapReturnType(function), function.getReturnType()),
expression.getLabelName()
);
return new NonLocalReturnInfo(function, expression.getLabelName());
}
}
return null;
@@ -5427,14 +5431,18 @@ The "returned" value of try expression with no finally is either the last expres
private static class NonLocalReturnInfo {
private final JvmKotlinType returnType;
private final CallableDescriptor descriptor;
private final String labelName;
private NonLocalReturnInfo(@NotNull JvmKotlinType type, @NotNull String name) {
returnType = type;
private NonLocalReturnInfo(@NotNull CallableDescriptor descriptor, @NotNull String name) {
this.descriptor = descriptor;
labelName = name;
}
private JvmKotlinType getJvmKotlinType(@NotNull KotlinTypeMapper typeMapper) {
return new JvmKotlinType(typeMapper.mapReturnType(descriptor), descriptor.getReturnType());
}
}
@NotNull