Fix generation of JS source maps for suspend functions
This commit is contained in:
@@ -114,7 +114,8 @@ data class CoroutineMetadata(
|
||||
val baseClassRef: JsExpression,
|
||||
val suspendObjectRef: JsExpression,
|
||||
val hasController: Boolean,
|
||||
val hasReceiver: Boolean
|
||||
val hasReceiver: Boolean,
|
||||
val psiElement: PsiElement?
|
||||
)
|
||||
|
||||
enum class TypeCheck {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -83,8 +83,8 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
||||
ifBlock.statements += x
|
||||
|
||||
val jointBlock = CoroutineBlock()
|
||||
thenExitBlock.statements += stateAndJump(jointBlock)
|
||||
elseExitBlock.statements += stateAndJump(jointBlock)
|
||||
thenExitBlock.statements += stateAndJump(jointBlock, x)
|
||||
elseExitBlock.statements += stateAndJump(jointBlock, x)
|
||||
currentBlock = jointBlock
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
||||
accept(inner)
|
||||
}
|
||||
if (successor in referencedBlocks) {
|
||||
currentBlock.statements += stateAndJump(successor)
|
||||
currentBlock.statements += stateAndJump(successor, x)
|
||||
currentBlock = successor
|
||||
}
|
||||
}
|
||||
@@ -118,25 +118,25 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
||||
override fun visitWhile(x: JsWhile) = splitIfNecessary(x) {
|
||||
val successor = CoroutineBlock()
|
||||
val bodyEntryBlock = CoroutineBlock()
|
||||
currentStatements += stateAndJump(bodyEntryBlock)
|
||||
currentStatements += stateAndJump(bodyEntryBlock, x)
|
||||
|
||||
currentBlock = bodyEntryBlock
|
||||
if (x.condition != JsLiteral.TRUE) {
|
||||
currentStatements += JsIf(JsAstUtils.notOptimized(x.condition), JsBlock(stateAndJump(successor))).apply { source = x.source }
|
||||
currentStatements += JsIf(JsAstUtils.notOptimized(x.condition), JsBlock(stateAndJump(successor, x))).apply { source = x.source }
|
||||
}
|
||||
|
||||
withBreakAndContinue(x, successor, bodyEntryBlock) {
|
||||
x.body.accept(this)
|
||||
}
|
||||
|
||||
currentStatements += stateAndJump(bodyEntryBlock)
|
||||
currentStatements += stateAndJump(bodyEntryBlock, x)
|
||||
currentBlock = successor
|
||||
}
|
||||
|
||||
override fun visitDoWhile(x: JsDoWhile) = splitIfNecessary(x) {
|
||||
val successor = CoroutineBlock()
|
||||
val bodyEntryBlock = CoroutineBlock()
|
||||
currentStatements += stateAndJump(bodyEntryBlock)
|
||||
currentStatements += stateAndJump(bodyEntryBlock, x)
|
||||
|
||||
currentBlock = bodyEntryBlock
|
||||
withBreakAndContinue(x, successor, bodyEntryBlock) {
|
||||
@@ -144,10 +144,10 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
||||
}
|
||||
|
||||
if (x.condition != JsLiteral.TRUE) {
|
||||
val jsIf = JsIf(JsAstUtils.notOptimized(x.condition), JsBlock(stateAndJump(successor))).apply { source = x.source }
|
||||
val jsIf = JsIf(JsAstUtils.notOptimized(x.condition), JsBlock(stateAndJump(successor, x))).apply { source = x.source }
|
||||
currentStatements.add(jsIf)
|
||||
}
|
||||
currentBlock.statements += stateAndJump(bodyEntryBlock)
|
||||
currentBlock.statements += stateAndJump(bodyEntryBlock, x)
|
||||
|
||||
currentBlock = successor
|
||||
}
|
||||
@@ -165,22 +165,22 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
||||
val increment = CoroutineBlock()
|
||||
val successor = CoroutineBlock()
|
||||
val bodyEntryBlock = CoroutineBlock()
|
||||
currentStatements += stateAndJump(bodyEntryBlock)
|
||||
currentStatements += stateAndJump(bodyEntryBlock, x)
|
||||
|
||||
currentBlock = bodyEntryBlock
|
||||
if (x.condition != null && x.condition != JsLiteral.TRUE) {
|
||||
currentStatements += JsIf(JsAstUtils.notOptimized(x.condition), JsBlock(stateAndJump(successor))).apply { source = x.source }
|
||||
currentStatements += JsIf(JsAstUtils.notOptimized(x.condition), JsBlock(stateAndJump(successor, x))).apply { source = x.source }
|
||||
}
|
||||
|
||||
withBreakAndContinue(x, successor, increment) {
|
||||
x.body.accept(this)
|
||||
}
|
||||
|
||||
currentStatements += stateAndJump(increment)
|
||||
currentStatements += stateAndJump(increment, x)
|
||||
currentBlock = increment
|
||||
|
||||
x.incrementExpression?.let { JsExpressionStatement(it).accept(this) }
|
||||
currentStatements += stateAndJump(bodyEntryBlock)
|
||||
currentStatements += stateAndJump(bodyEntryBlock, x)
|
||||
|
||||
currentBlock = successor
|
||||
}
|
||||
@@ -189,7 +189,7 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
||||
val targetStatement = breakContinueTargetStatements[x]!!
|
||||
val (targetBlock, targetTryDepth) = breakTargets[targetStatement]!!
|
||||
referencedBlocks += targetBlock
|
||||
jumpWithFinally(targetTryDepth + 1, targetBlock)
|
||||
jumpWithFinally(targetTryDepth + 1, targetBlock, x)
|
||||
currentStatements += jump()
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
||||
val targetStatement = breakContinueTargetStatements[x]!!
|
||||
val (targetBlock, targetTryDepth) = continueTargets[targetStatement]!!
|
||||
referencedBlocks += targetBlock
|
||||
jumpWithFinally(targetTryDepth + 1, targetBlock)
|
||||
jumpWithFinally(targetTryDepth + 1, targetBlock, x)
|
||||
currentStatements += jump()
|
||||
}
|
||||
|
||||
@@ -205,10 +205,10 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
||||
* When we perform break, continue or return, we can leave try blocks, so we should update $exceptionHandler correspondingly.
|
||||
* Also, these try blocks can contain finally clauses, therefore we need to update $finallyPath as well.
|
||||
*/
|
||||
private fun jumpWithFinally(targetTryDepth: Int, successor: CoroutineBlock) {
|
||||
private fun jumpWithFinally(targetTryDepth: Int, successor: CoroutineBlock, fromNode: JsNode) {
|
||||
if (targetTryDepth < tryStack.size) {
|
||||
val tryBlock = tryStack[targetTryDepth]
|
||||
currentStatements += exceptionState(tryBlock.catchBlock)
|
||||
currentStatements += exceptionState(tryBlock.catchBlock, fromNode)
|
||||
}
|
||||
|
||||
val relativeFinallyPath = relativeFinallyPath(targetTryDepth)
|
||||
@@ -216,7 +216,7 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
||||
if (fullPath.size > 1) {
|
||||
currentStatements += updateFinallyPath(fullPath.drop(1))
|
||||
}
|
||||
currentStatements += state(fullPath[0])
|
||||
currentStatements += state(fullPath[0], fromNode)
|
||||
}
|
||||
|
||||
override fun visitTry(x: JsTry) = splitIfNecessary(x) {
|
||||
@@ -231,19 +231,19 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
||||
|
||||
val oldCatchBlock = currentCatchBlock
|
||||
currentCatchBlock = catchBlock
|
||||
currentStatements += exceptionState(catchBlock)
|
||||
currentStatements += exceptionState(catchBlock, x)
|
||||
|
||||
x.tryBlock.statements.forEach { it.accept(this) }
|
||||
|
||||
currentStatements += exceptionState(oldCatchBlock)
|
||||
currentStatements += exceptionState(oldCatchBlock, x)
|
||||
currentCatchBlock = oldCatchBlock
|
||||
|
||||
if (finallyNode != null) {
|
||||
currentStatements += updateFinallyPath(listOf(successor))
|
||||
currentStatements += stateAndJump(finallyBlock)
|
||||
currentStatements += stateAndJump(finallyBlock, x)
|
||||
}
|
||||
else {
|
||||
currentStatements += stateAndJump(successor)
|
||||
currentStatements += stateAndJump(successor, x)
|
||||
}
|
||||
|
||||
// Handle catch node
|
||||
@@ -251,10 +251,10 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
||||
|
||||
if (finallyNode != null) {
|
||||
currentStatements += updateFinallyPath(listOf(oldCatchBlock))
|
||||
currentStatements += if (catchNode != null) exceptionState(finallyBlock) else stateAndJump(finallyBlock)
|
||||
currentStatements += if (catchNode != null) exceptionState(finallyBlock, x) else stateAndJump(finallyBlock, x)
|
||||
}
|
||||
else {
|
||||
currentStatements += if (catchNode != null) exceptionState(oldCatchBlock) else stateAndJump(oldCatchBlock)
|
||||
currentStatements += if (catchNode != null) exceptionState(oldCatchBlock, x) else stateAndJump(oldCatchBlock, x)
|
||||
}
|
||||
|
||||
if (catchNode != null) {
|
||||
@@ -263,11 +263,11 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
||||
catchNode.body.statements.forEach { it.accept(this) }
|
||||
|
||||
if (finallyNode == null) {
|
||||
currentStatements += stateAndJump(successor)
|
||||
currentStatements += stateAndJump(successor, x)
|
||||
}
|
||||
else {
|
||||
currentStatements += updateFinallyPath(listOf(successor))
|
||||
currentStatements += stateAndJump(finallyBlock)
|
||||
currentStatements += stateAndJump(finallyBlock, x)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,7 +314,7 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
||||
val isInFinally = hasEnclosingFinallyBlock()
|
||||
if (isInFinally) {
|
||||
val returnBlock = CoroutineBlock()
|
||||
jumpWithFinally(0, returnBlock)
|
||||
jumpWithFinally(0, returnBlock, x)
|
||||
val returnExpression = x.expression
|
||||
val returnFieldRef = if (returnExpression != null) {
|
||||
val ref = JsNameRef(context.returnValueFieldName, JsAstUtils.stateMachineReceiver())
|
||||
@@ -343,47 +343,51 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
||||
if (assignment != null) {
|
||||
val rhs = assignment.second
|
||||
if (rhs.isSuspend) {
|
||||
handleSuspend(expression)
|
||||
handleSuspend(expression, rhs)
|
||||
return null
|
||||
}
|
||||
}
|
||||
else if (expression.isSuspend) {
|
||||
handleSuspend(expression)
|
||||
handleSuspend(expression, expression)
|
||||
return null
|
||||
}
|
||||
return expression
|
||||
}
|
||||
|
||||
private fun handleSuspend(invocation: JsExpression) {
|
||||
private fun handleSuspend(invocation: JsExpression, sourceNode: JsExpression) {
|
||||
val psi = sourceNode.source ?: invocation.source
|
||||
|
||||
val nextBlock = CoroutineBlock()
|
||||
currentStatements += state(nextBlock)
|
||||
currentStatements += state(nextBlock, invocation)
|
||||
|
||||
val resultRef = JsNameRef(context.metadata.resultName, JsAstUtils.stateMachineReceiver()).apply {
|
||||
sideEffects = SideEffectKind.DEPENDS_ON_STATE
|
||||
}
|
||||
val invocationStatement = JsAstUtils.assignment(resultRef, invocation).makeStmt()
|
||||
val suspendCondition = JsAstUtils.equality(resultRef.deepCopy(), context.metadata.suspendObjectRef.deepCopy())
|
||||
val suspendIfNeeded = JsIf(suspendCondition, JsReturn(context.metadata.suspendObjectRef.deepCopy()))
|
||||
currentStatements += listOf(invocationStatement, suspendIfNeeded, JsBreak())
|
||||
val suspendCondition = JsAstUtils.equality(resultRef.deepCopy(), context.metadata.suspendObjectRef.deepCopy()).source(psi)
|
||||
val suspendIfNeeded = JsIf(suspendCondition, JsReturn(context.metadata.suspendObjectRef.deepCopy().source(psi)))
|
||||
currentStatements += listOf(invocationStatement, suspendIfNeeded, JsBreak().apply { source = psi })
|
||||
currentBlock = nextBlock
|
||||
}
|
||||
|
||||
private fun state(target: CoroutineBlock): List<JsStatement> {
|
||||
private fun state(target: CoroutineBlock, fromExpression: JsNode): List<JsStatement> {
|
||||
val placeholder = JsDebugger()
|
||||
placeholder.targetBlock = target
|
||||
placeholder.source = fromExpression.source
|
||||
|
||||
return listOf(placeholder)
|
||||
}
|
||||
|
||||
private fun jump() = JsContinue()
|
||||
|
||||
private fun stateAndJump(target: CoroutineBlock): List<JsStatement> {
|
||||
return state(target) + jump()
|
||||
private fun stateAndJump(target: CoroutineBlock, fromNode: JsNode): List<JsStatement> {
|
||||
return state(target, fromNode) + jump()
|
||||
}
|
||||
|
||||
private fun exceptionState(target: CoroutineBlock): List<JsStatement> {
|
||||
private fun exceptionState(target: CoroutineBlock, fromNode: JsNode): List<JsStatement> {
|
||||
val placeholder = JsDebugger()
|
||||
placeholder.targetExceptionBlock = target
|
||||
placeholder.source = fromNode
|
||||
|
||||
return listOf(placeholder)
|
||||
}
|
||||
|
||||
+19
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.js.coroutine
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.coroutineMetadata
|
||||
import org.jetbrains.kotlin.js.inline.clean.FunctionPostProcessor
|
||||
@@ -57,6 +58,8 @@ class CoroutineFunctionTransformer(private val program: JsProgram, private val f
|
||||
statements: MutableList<JsStatement>,
|
||||
globalCatchBlockIndex: Int
|
||||
) {
|
||||
val psiElement = context.metadata.psiElement
|
||||
|
||||
val constructor = JsFunction(function.scope.parent, JsBlock(), "Continuation")
|
||||
constructor.name = className
|
||||
if (context.metadata.hasReceiver) {
|
||||
@@ -80,17 +83,17 @@ class CoroutineFunctionTransformer(private val program: JsProgram, private val f
|
||||
|
||||
constructor.body.statements.run {
|
||||
val baseClass = context.metadata.baseClassRef.deepCopy()
|
||||
this += JsInvocation(Namer.getFunctionCallRef(baseClass), JsLiteral.THIS, interceptorRef).makeStmt()
|
||||
this += JsInvocation(Namer.getFunctionCallRef(baseClass), JsLiteral.THIS, interceptorRef).source(psiElement).makeStmt()
|
||||
if (controllerName != null) {
|
||||
assignToField(context.controllerFieldName, controllerName.makeRef())
|
||||
assignToField(context.controllerFieldName, controllerName.makeRef(), psiElement)
|
||||
}
|
||||
assignToField(context.metadata.exceptionStateName, program.getNumberLiteral(globalCatchBlockIndex))
|
||||
assignToField(context.metadata.exceptionStateName, program.getNumberLiteral(globalCatchBlockIndex), psiElement)
|
||||
if (context.metadata.hasReceiver) {
|
||||
assignToField(context.receiverFieldName, context.receiverFieldName.makeRef())
|
||||
assignToField(context.receiverFieldName, context.receiverFieldName.makeRef(), psiElement)
|
||||
}
|
||||
for (localVariable in localVariables) {
|
||||
val value = if (localVariable !in parameterNames) Namer.getUndefinedExpression() else localVariable.makeRef()
|
||||
assignToField(context.getFieldName(localVariable), value)
|
||||
assignToField(context.getFieldName(localVariable), value, psiElement)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +147,8 @@ class CoroutineFunctionTransformer(private val program: JsProgram, private val f
|
||||
}
|
||||
|
||||
private fun generateCoroutineInstantiation(context: CoroutineTransformationContext) {
|
||||
val instantiation = JsNew(className.makeRef())
|
||||
val psiElement = context.metadata.psiElement
|
||||
val instantiation = JsNew(className.makeRef()).apply { source = psiElement }
|
||||
if (context.metadata.hasReceiver) {
|
||||
instantiation.arguments += JsLiteral.THIS
|
||||
}
|
||||
@@ -163,9 +167,13 @@ class CoroutineFunctionTransformer(private val program: JsProgram, private val f
|
||||
val instanceName = JsScope.declareTemporaryName("instance")
|
||||
functionWithBody.body.statements += JsAstUtils.newVar(instanceName, instantiation)
|
||||
|
||||
val invokeResume = JsReturn(JsInvocation(JsNameRef(context.metadata.doResumeName, instanceName.makeRef()), JsLiteral.NULL))
|
||||
val invokeResume = JsReturn(JsInvocation(JsNameRef(context.metadata.doResumeName, instanceName.makeRef()), JsLiteral.NULL)
|
||||
.source(psiElement))
|
||||
|
||||
functionWithBody.body.statements += JsIf(suspendedName.makeRef(), JsReturn(instanceName.makeRef()), invokeResume)
|
||||
functionWithBody.body.statements += JsIf(
|
||||
suspendedName.makeRef().source(psiElement),
|
||||
JsReturn(instanceName.makeRef().source(psiElement)),
|
||||
invokeResume)
|
||||
}
|
||||
|
||||
private fun generateCoroutineBody(
|
||||
@@ -208,8 +216,8 @@ class CoroutineFunctionTransformer(private val program: JsProgram, private val f
|
||||
})
|
||||
}
|
||||
|
||||
private fun MutableList<JsStatement>.assignToField(fieldName: JsName, value: JsExpression) {
|
||||
this += JsAstUtils.assignment(JsNameRef(fieldName, JsLiteral.THIS), value).makeStmt()
|
||||
private fun MutableList<JsStatement>.assignToField(fieldName: JsName, value: JsExpression, psiElement: PsiElement?) {
|
||||
this += JsAstUtils.assignment(JsNameRef(fieldName, JsLiteral.THIS), value).source(psiElement).makeStmt()
|
||||
}
|
||||
|
||||
private fun MutableList<JsStatement>.assignToPrototype(fieldName: JsName, value: JsExpression) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -122,7 +122,7 @@ fun List<CoroutineBlock>.replaceCoroutineFlowStatements(context: CoroutineTransf
|
||||
if (target != null) {
|
||||
val lhs = JsNameRef(context.metadata.stateName, JsAstUtils.stateMachineReceiver())
|
||||
val rhs = program.getNumberLiteral(blockIndexes[target]!!)
|
||||
ctx.replaceMe(JsExpressionStatement(JsAstUtils.assignment(lhs, rhs)).apply {
|
||||
ctx.replaceMe(JsExpressionStatement(JsAstUtils.assignment(lhs, rhs).source(x.source)).apply {
|
||||
targetBlock = true
|
||||
})
|
||||
}
|
||||
@@ -131,7 +131,7 @@ fun List<CoroutineBlock>.replaceCoroutineFlowStatements(context: CoroutineTransf
|
||||
if (exceptionTarget != null) {
|
||||
val lhs = JsNameRef(context.metadata.exceptionStateName, JsAstUtils.stateMachineReceiver())
|
||||
val rhs = program.getNumberLiteral(blockIndexes[exceptionTarget]!!)
|
||||
ctx.replaceMe(JsExpressionStatement(JsAstUtils.assignment(lhs, rhs)).apply {
|
||||
ctx.replaceMe(JsExpressionStatement(JsAstUtils.assignment(lhs, rhs).source(x.source)).apply {
|
||||
targetExceptionBlock = true
|
||||
})
|
||||
}
|
||||
@@ -141,7 +141,7 @@ fun List<CoroutineBlock>.replaceCoroutineFlowStatements(context: CoroutineTransf
|
||||
if (finallyPath.isNotEmpty()) {
|
||||
val lhs = JsNameRef(context.metadata.finallyPathName, JsAstUtils.stateMachineReceiver())
|
||||
val rhs = JsArrayLiteral(finallyPath.map { program.getNumberLiteral(blockIndexes[it]!!) })
|
||||
ctx.replaceMe(JsExpressionStatement(JsAstUtils.assignment(lhs, rhs)).apply {
|
||||
ctx.replaceMe(JsExpressionStatement(JsAstUtils.assignment(lhs, rhs).source(x.source)).apply {
|
||||
this.finallyPath = true
|
||||
})
|
||||
}
|
||||
@@ -222,12 +222,14 @@ fun JsBlock.replaceSpecialReferences(context: CoroutineTransformationContext) {
|
||||
|
||||
x.coroutineController -> {
|
||||
ctx.replaceMe(JsNameRef(context.controllerFieldName, x.qualifier).apply {
|
||||
source = x.source
|
||||
sideEffects = SideEffectKind.PURE
|
||||
})
|
||||
}
|
||||
|
||||
x.coroutineResult -> {
|
||||
ctx.replaceMe(JsNameRef(context.metadata.resultName, x.qualifier).apply {
|
||||
source = x.source
|
||||
sideEffects = SideEffectKind.DEPENDS_ON_STATE
|
||||
})
|
||||
}
|
||||
@@ -262,7 +264,7 @@ fun JsBlock.replaceLocalVariables(context: CoroutineTransformationContext, local
|
||||
override fun endVisit(x: JsNameRef, ctx: JsContext<in JsNode>) {
|
||||
if (x.qualifier == null && x.name in localVariables) {
|
||||
val fieldName = context.getFieldName(x.name!!)
|
||||
ctx.replaceMe(JsNameRef(fieldName, JsLiteral.THIS))
|
||||
ctx.replaceMe(JsNameRef(fieldName, JsLiteral.THIS).source(x.source))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,12 @@ public class JsLineNumberTestGenerated extends AbstractJsLineNumberTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("coroutine.kt")
|
||||
public void testCoroutine() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/coroutine.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inlining.kt")
|
||||
public void testInlining() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/inlining.kt");
|
||||
|
||||
+7
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -136,10 +136,14 @@ private fun translateFunctionCall(
|
||||
|
||||
if (resolvedCall.resultingDescriptor.isSuspend) {
|
||||
if (context.isInStateMachine) {
|
||||
context.currentBlock.statements += JsAstUtils.asSyntheticStatement(callExpression.apply { isSuspend = true })
|
||||
val coroutineRef = TranslationUtils.translateContinuationArgument(context)
|
||||
context.currentBlock.statements += JsAstUtils.asSyntheticStatement(callExpression.apply {
|
||||
isSuspend = true
|
||||
source = resolvedCall.call.callElement
|
||||
})
|
||||
val coroutineRef = TranslationUtils.translateContinuationArgument(context).apply { source = resolvedCall.call.callElement }
|
||||
return context.defineTemporary(JsNameRef("\$\$coroutineResult\$\$", coroutineRef).apply {
|
||||
sideEffects = SideEffectKind.DEPENDS_ON_STATE
|
||||
source = resolvedCall.call.callElement
|
||||
coroutineResult = true
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.simpleReturnFunc
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasOrInheritsParametersWithDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
fun generateDelegateCall(
|
||||
@@ -184,6 +185,7 @@ fun JsFunction.fillCoroutineMetadata(
|
||||
resultName = getCoroutinePropertyName("result"),
|
||||
exceptionName = getCoroutinePropertyName("exception"),
|
||||
hasController = hasController,
|
||||
hasReceiver = descriptor.dispatchReceiverParameter != null
|
||||
hasReceiver = descriptor.dispatchReceiverParameter != null,
|
||||
psiElement = descriptor.source.getPsi()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import kotlin.coroutines.experimental.*
|
||||
import kotlin.coroutines.experimental.intrinsics.*
|
||||
|
||||
suspend fun foo(value: Int): Int = suspendCoroutineOrReturn { c ->
|
||||
c.resume(value)
|
||||
COROUTINE_SUSPENDED
|
||||
}
|
||||
|
||||
suspend fun bar(): Unit {
|
||||
println("!")
|
||||
val a = foo(2)
|
||||
println("!")
|
||||
val b = foo(3)
|
||||
println(a + b)
|
||||
}
|
||||
|
||||
// LINES: 4 5 6 * 9 9 9 9 9 9 9 9 * 10 11 11 11 11 11 * 11 12 13 13 13 13 13 13 14
|
||||
Reference in New Issue
Block a user