Fix verify error with 'return when/if/try' in suspend function

The problem appears for tail-optimized suspend functions,
we erroneously assumed that when/if/try expressions in tail-call
position have simple types like `I` while actually, they can return SUSPENDED
object, i.e. must have `java/lang/Object` as return type.

But this only concerns branching operations in tail-call position,
so we have to make an additional analysis for remembering whether
a given expression is in a tail-call position.

Also, it's important here that we now assume
the return type of the current function  as `java/lang/Object`
that is necessary to avoid wrong checkcasts.

 #KT-15364 Fixed
This commit is contained in:
Denis Zharkov
2017-01-12 15:34:31 +03:00
parent de9c41c412
commit 2286027bed
14 changed files with 324 additions and 32 deletions
@@ -170,9 +170,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
@NotNull
private Type getBoxedReturnTypeForSuspend(FunctionDescriptor descriptorForSuspend) {
assert descriptorForSuspend.getReturnType() != null : "Uninitialized suspend return type";
return AsmUtil.boxType(typeMapper.mapType(descriptorForSuspend.getReturnType()));
private static Type getBoxedReturnTypeForSuspend(FunctionDescriptor descriptorForSuspend) {
return AsmTypes.OBJECT_TYPE;
}
@Nullable
@@ -454,6 +453,16 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
return typeMapper.mapType(type);
}
@NotNull
private Type expressionTypeForBranchingOperation(@Nullable KtExpression expression) {
if (context.getFunctionDescriptor().isSuspend() &&
!CoroutineCodegenUtilKt.isStateMachineNeeded(context.getFunctionDescriptor(), bindingContext) &&
Boolean.TRUE.equals(bindingContext.get(IS_TAIL_EXPRESSION_IN_SUSPEND_FUNCTION, expression))) {
return AsmTypes.OBJECT_TYPE;
}
return expressionType(expression);
}
@NotNull
public Type expressionType(@Nullable KtExpression expression) {
return CodegenUtilKt.asmType(expression, typeMapper, bindingContext);
@@ -494,7 +503,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
/* package */ StackValue generateIfExpression(@NotNull final KtIfExpression expression, final boolean isStatement) {
final Type asmType = isStatement ? Type.VOID_TYPE : expressionType(expression);
final Type asmType = isStatement ? Type.VOID_TYPE : expressionTypeForBranchingOperation(expression);
final StackValue condition = gen(expression.getCondition());
final KtExpression thenExpression = expression.getThen();
@@ -4284,9 +4293,7 @@ The "returned" value of try expression with no finally is either the last expres
(or blocks).
*/
KotlinType jetType = bindingContext.getType(expression);
assert jetType != null;
final Type expectedAsmType = isStatement ? Type.VOID_TYPE : asmType(jetType);
final Type expectedAsmType = isStatement ? Type.VOID_TYPE : expressionTypeForBranchingOperation(expression);
return StackValue.operation(expectedAsmType, new Function1<InstructionAdapter, Unit>() {
@Override
@@ -4559,7 +4566,7 @@ The "returned" value of try expression with no finally is either the last expres
final KtExpression expr = expression.getSubjectExpression();
final Type subjectType = expressionType(expr);
final Type resultType = isStatement ? Type.VOID_TYPE : expressionType(expression);
final Type resultType = isStatement ? Type.VOID_TYPE : expressionTypeForBranchingOperation(expression);
return StackValue.operation(resultType, new Function1<InstructionAdapter, Unit>() {
@Override