KT-27524 Don't box (some) inline classes in suspend fun return
If an inline class is mapped to a reference type (or an array), it's Ok to treat JVM view on a suspend function as returning a value of corresponding inline class (although in reality it returns 'Any?' because of COROUTINE_SUSPENDED).
This commit is contained in:
@@ -37,7 +37,7 @@ interface Callable {
|
||||
|
||||
fun invokeMethodWithArguments(resolvedCall: ResolvedCall<*>, receiver: StackValue, codegen: ExpressionCodegen): StackValue {
|
||||
// it's important to use unsubstituted return type here to unbox value if it comes from type variable
|
||||
return StackValue.functionCall(returnType, resolvedCall.resultingDescriptor.original.returnType) {
|
||||
return StackValue.functionCall(returnType, returnKotlinType ?: resolvedCall.resultingDescriptor.original.returnType) {
|
||||
codegen.invokeMethodWithArguments(this, resolvedCall, receiver)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1648,7 +1648,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
else {
|
||||
returnType = this.returnType;
|
||||
returnKotlinType = this.context.getFunctionDescriptor().getReturnType();
|
||||
returnKotlinType = typeMapper.getReturnValueType(this.context.getFunctionDescriptor());
|
||||
}
|
||||
StackValue valueToReturn = returnedExpression != null ? gen(returnedExpression) : StackValue.none();
|
||||
|
||||
@@ -1701,7 +1701,10 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
BindingContextUtils.getContainingFunctionSkipFunctionLiterals(descriptor, true).getFirst();
|
||||
//FIRST_FUN_LABEL to prevent clashing with existing labels
|
||||
return new NonLocalReturnInfo(
|
||||
new JvmKotlinType(typeMapper.mapReturnType(containingFunction), containingFunction.getReturnType()),
|
||||
new JvmKotlinType(
|
||||
typeMapper.mapReturnType(containingFunction),
|
||||
typeMapper.getReturnValueType(containingFunction)
|
||||
),
|
||||
FIRST_FUN_LABEL
|
||||
);
|
||||
} else {
|
||||
@@ -1739,7 +1742,9 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
: returnType;
|
||||
|
||||
KotlinType kotlinTypeForExpression =
|
||||
isBlockedNamedFunction || isVoidCoroutineLambda ? null : context.getFunctionDescriptor().getReturnType();
|
||||
isBlockedNamedFunction || isVoidCoroutineLambda
|
||||
? null
|
||||
: typeMapper.getReturnValueType(context.getFunctionDescriptor());
|
||||
|
||||
gen(expr, typeForExpression, kotlinTypeForExpression);
|
||||
|
||||
|
||||
@@ -362,6 +362,19 @@ class KotlinTypeMapper @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun getReturnValueType(functionDescriptor: FunctionDescriptor): KotlinType =
|
||||
getActualReturnTypeForSuspendFunctionWithInlineClassReturnTypeHack(functionDescriptor)
|
||||
?: functionDescriptor.returnType!!
|
||||
|
||||
private fun getActualReturnTypeForSuspendFunctionWithInlineClassReturnTypeHack(functionDescriptor: FunctionDescriptor): KotlinType? {
|
||||
val originalSuspendFunctionForJvmView = functionDescriptor.unwrapInitialDescriptorForSuspendFunction()
|
||||
if (originalSuspendFunctionForJvmView === functionDescriptor) return null
|
||||
val originalReturnType = originalSuspendFunctionForJvmView.returnType!!
|
||||
if (!originalReturnType.isInlineClassType()) return null
|
||||
val jvmReturnType = mapType(originalReturnType)
|
||||
return if (AsmUtil.isPrimitive(jvmReturnType)) null else originalReturnType
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun mapToCallableMethod(
|
||||
descriptor: FunctionDescriptor,
|
||||
@@ -431,7 +444,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
|
||||
invokeOpcode = INVOKESTATIC
|
||||
val originalDescriptor = descriptor.original
|
||||
signature = mapSignatureSkipGeneric(originalDescriptor, OwnerKind.DEFAULT_IMPLS)
|
||||
returnKotlinType = originalDescriptor.returnType
|
||||
returnKotlinType = getReturnValueType(originalDescriptor)
|
||||
if (descriptor is AccessorForCallableDescriptor<*> && descriptor.calleeDescriptor.hasJvmDefaultAnnotation()) {
|
||||
owner = mapClass(functionParent)
|
||||
isInterfaceMember = true
|
||||
@@ -482,7 +495,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
|
||||
skipGenericSignature = true,
|
||||
hasSpecialBridge = false
|
||||
)
|
||||
returnKotlinType = functionToCall.returnType
|
||||
returnKotlinType = getReturnValueType(functionToCall)
|
||||
|
||||
val receiver = if (currentIsInterface && !originalIsInterface || functionParent is FunctionClassDescriptor)
|
||||
declarationOwner
|
||||
@@ -495,7 +508,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
|
||||
} else {
|
||||
val originalDescriptor = functionDescriptor.original
|
||||
signature = mapSignatureSkipGeneric(originalDescriptor)
|
||||
returnKotlinType = originalDescriptor.returnType
|
||||
returnKotlinType = getReturnValueType(originalDescriptor)
|
||||
owner = mapOwner(functionDescriptor)
|
||||
ownerForDefaultImpl = owner
|
||||
baseMethodDescriptor = functionDescriptor
|
||||
|
||||
Reference in New Issue
Block a user