Fix problem with missing handleResult call

At first we try to resolve 'handleResult' just as last expression
in a lambda is first argument, then if results are unsuccessful
try resolve 'handleResult' with fake Unit expression

 #KT-12969 Fixed
This commit is contained in:
Denis Zharkov
2016-07-04 18:07:16 +03:00
parent 888db4b3b5
commit a420fda825
3 changed files with 57 additions and 10 deletions
@@ -72,21 +72,34 @@ fun FakeCallResolver.resolveCoroutineHandleResultCallIfNeeded(
// should be Continuation<Nothing> // should be Continuation<Nothing>
functionDescriptor.builtIns.nothingType) functionDescriptor.builtIns.nothingType)
fun tryToResolveCall(firstArgument: KtExpression): Boolean {
val resolutionResults = resolveFakeCall(
context.replaceBindingTrace(temporaryBindingTrace), functionDescriptor.extensionReceiverParameter!!.value,
OperatorNameConventions.COROUTINE_HANDLE_RESULT, callElement, callElement, FakeCallKind.OTHER,
listOf(firstArgument, continuation))
if (resolutionResults.isSuccess && resolutionResults.resultingDescriptor.isOperator) {
context.trace.record(BindingContext.RETURN_HANDLE_RESULT_RESOLVED_CALL, callElement, resolutionResults.resultingCall)
return true
}
return false
}
val unitExpression = ExpressionTypingUtils.createFakeExpressionOfType(
callElement.project, temporaryBindingTrace, "unit", functionDescriptor.builtIns.unitType)
val firstArgument = val firstArgument =
if (expressionToReturn == null || info != null && info.type != null && KotlinBuiltIns.isUnit(info.type)) if (expressionToReturn == null || info != null && info.type != null && KotlinBuiltIns.isUnit(info.type))
ExpressionTypingUtils.createFakeExpressionOfType( unitExpression
callElement.project, temporaryBindingTrace, "unit", functionDescriptor.builtIns.unitType) else
else expressionToReturn expressionToReturn
val resolutionResults = resolveFakeCall( if (!tryToResolveCall(firstArgument) && firstArgument === expressionToReturn) {
context.replaceBindingTrace(temporaryBindingTrace), functionDescriptor.extensionReceiverParameter!!.value, tryToResolveCall(unitExpression)
OperatorNameConventions.COROUTINE_HANDLE_RESULT, callElement, callElement, FakeCallKind.OTHER,
listOf(firstArgument, continuation))
if (resolutionResults.isSuccess && resolutionResults.resultingDescriptor.isOperator) {
context.trace.record(BindingContext.RETURN_HANDLE_RESULT_RESOLVED_CALL, callElement, resolutionResults.resultingCall)
} }
} }
fun KotlinType.isValidContinuation() = fun KotlinType.isValidContinuation() =
(constructor.declarationDescriptor as? ClassDescriptor)?.fqNameUnsafe == DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME.toUnsafe() (constructor.declarationDescriptor as? ClassDescriptor)?.fqNameUnsafe == DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME.toUnsafe()
@@ -0,0 +1,28 @@
class Controller {
var isCompleted = false
suspend fun suspendHere(x: Continuation<String>) {
x.resume("OK")
}
operator fun handleResult(x: Unit, y: Continuation<Nothing>) {
isCompleted = true
}
}
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
val controller = Controller()
c(controller).resume(Unit)
if (!controller.isCompleted) throw java.lang.RuntimeException("fail")
}
fun box(): String {
builder {
"OK"
}
builder {
suspendHere()
}
return "OK"
}
@@ -4189,6 +4189,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("handleResultNonUnitExpression.kt")
public void testHandleResultNonUnitExpression() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/handleResultNonUnitExpression.kt");
doTest(fileName);
}
@TestMetadata("illegalState.kt") @TestMetadata("illegalState.kt")
public void testIllegalState() throws Exception { public void testIllegalState() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/illegalState.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/illegalState.kt");