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 baseClassRef: JsExpression,
|
||||||
val suspendObjectRef: JsExpression,
|
val suspendObjectRef: JsExpression,
|
||||||
val hasController: Boolean,
|
val hasController: Boolean,
|
||||||
val hasReceiver: Boolean
|
val hasReceiver: Boolean,
|
||||||
|
val psiElement: PsiElement?
|
||||||
)
|
)
|
||||||
|
|
||||||
enum class TypeCheck {
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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
|
ifBlock.statements += x
|
||||||
|
|
||||||
val jointBlock = CoroutineBlock()
|
val jointBlock = CoroutineBlock()
|
||||||
thenExitBlock.statements += stateAndJump(jointBlock)
|
thenExitBlock.statements += stateAndJump(jointBlock, x)
|
||||||
elseExitBlock.statements += stateAndJump(jointBlock)
|
elseExitBlock.statements += stateAndJump(jointBlock, x)
|
||||||
currentBlock = jointBlock
|
currentBlock = jointBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
|||||||
accept(inner)
|
accept(inner)
|
||||||
}
|
}
|
||||||
if (successor in referencedBlocks) {
|
if (successor in referencedBlocks) {
|
||||||
currentBlock.statements += stateAndJump(successor)
|
currentBlock.statements += stateAndJump(successor, x)
|
||||||
currentBlock = successor
|
currentBlock = successor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,25 +118,25 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
|||||||
override fun visitWhile(x: JsWhile) = splitIfNecessary(x) {
|
override fun visitWhile(x: JsWhile) = splitIfNecessary(x) {
|
||||||
val successor = CoroutineBlock()
|
val successor = CoroutineBlock()
|
||||||
val bodyEntryBlock = CoroutineBlock()
|
val bodyEntryBlock = CoroutineBlock()
|
||||||
currentStatements += stateAndJump(bodyEntryBlock)
|
currentStatements += stateAndJump(bodyEntryBlock, x)
|
||||||
|
|
||||||
currentBlock = bodyEntryBlock
|
currentBlock = bodyEntryBlock
|
||||||
if (x.condition != JsLiteral.TRUE) {
|
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) {
|
withBreakAndContinue(x, successor, bodyEntryBlock) {
|
||||||
x.body.accept(this)
|
x.body.accept(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
currentStatements += stateAndJump(bodyEntryBlock)
|
currentStatements += stateAndJump(bodyEntryBlock, x)
|
||||||
currentBlock = successor
|
currentBlock = successor
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitDoWhile(x: JsDoWhile) = splitIfNecessary(x) {
|
override fun visitDoWhile(x: JsDoWhile) = splitIfNecessary(x) {
|
||||||
val successor = CoroutineBlock()
|
val successor = CoroutineBlock()
|
||||||
val bodyEntryBlock = CoroutineBlock()
|
val bodyEntryBlock = CoroutineBlock()
|
||||||
currentStatements += stateAndJump(bodyEntryBlock)
|
currentStatements += stateAndJump(bodyEntryBlock, x)
|
||||||
|
|
||||||
currentBlock = bodyEntryBlock
|
currentBlock = bodyEntryBlock
|
||||||
withBreakAndContinue(x, successor, bodyEntryBlock) {
|
withBreakAndContinue(x, successor, bodyEntryBlock) {
|
||||||
@@ -144,10 +144,10 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (x.condition != JsLiteral.TRUE) {
|
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)
|
currentStatements.add(jsIf)
|
||||||
}
|
}
|
||||||
currentBlock.statements += stateAndJump(bodyEntryBlock)
|
currentBlock.statements += stateAndJump(bodyEntryBlock, x)
|
||||||
|
|
||||||
currentBlock = successor
|
currentBlock = successor
|
||||||
}
|
}
|
||||||
@@ -165,22 +165,22 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
|||||||
val increment = CoroutineBlock()
|
val increment = CoroutineBlock()
|
||||||
val successor = CoroutineBlock()
|
val successor = CoroutineBlock()
|
||||||
val bodyEntryBlock = CoroutineBlock()
|
val bodyEntryBlock = CoroutineBlock()
|
||||||
currentStatements += stateAndJump(bodyEntryBlock)
|
currentStatements += stateAndJump(bodyEntryBlock, x)
|
||||||
|
|
||||||
currentBlock = bodyEntryBlock
|
currentBlock = bodyEntryBlock
|
||||||
if (x.condition != null && x.condition != JsLiteral.TRUE) {
|
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) {
|
withBreakAndContinue(x, successor, increment) {
|
||||||
x.body.accept(this)
|
x.body.accept(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
currentStatements += stateAndJump(increment)
|
currentStatements += stateAndJump(increment, x)
|
||||||
currentBlock = increment
|
currentBlock = increment
|
||||||
|
|
||||||
x.incrementExpression?.let { JsExpressionStatement(it).accept(this) }
|
x.incrementExpression?.let { JsExpressionStatement(it).accept(this) }
|
||||||
currentStatements += stateAndJump(bodyEntryBlock)
|
currentStatements += stateAndJump(bodyEntryBlock, x)
|
||||||
|
|
||||||
currentBlock = successor
|
currentBlock = successor
|
||||||
}
|
}
|
||||||
@@ -189,7 +189,7 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
|||||||
val targetStatement = breakContinueTargetStatements[x]!!
|
val targetStatement = breakContinueTargetStatements[x]!!
|
||||||
val (targetBlock, targetTryDepth) = breakTargets[targetStatement]!!
|
val (targetBlock, targetTryDepth) = breakTargets[targetStatement]!!
|
||||||
referencedBlocks += targetBlock
|
referencedBlocks += targetBlock
|
||||||
jumpWithFinally(targetTryDepth + 1, targetBlock)
|
jumpWithFinally(targetTryDepth + 1, targetBlock, x)
|
||||||
currentStatements += jump()
|
currentStatements += jump()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,7 +197,7 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
|||||||
val targetStatement = breakContinueTargetStatements[x]!!
|
val targetStatement = breakContinueTargetStatements[x]!!
|
||||||
val (targetBlock, targetTryDepth) = continueTargets[targetStatement]!!
|
val (targetBlock, targetTryDepth) = continueTargets[targetStatement]!!
|
||||||
referencedBlocks += targetBlock
|
referencedBlocks += targetBlock
|
||||||
jumpWithFinally(targetTryDepth + 1, targetBlock)
|
jumpWithFinally(targetTryDepth + 1, targetBlock, x)
|
||||||
currentStatements += jump()
|
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.
|
* 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.
|
* 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) {
|
if (targetTryDepth < tryStack.size) {
|
||||||
val tryBlock = tryStack[targetTryDepth]
|
val tryBlock = tryStack[targetTryDepth]
|
||||||
currentStatements += exceptionState(tryBlock.catchBlock)
|
currentStatements += exceptionState(tryBlock.catchBlock, fromNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
val relativeFinallyPath = relativeFinallyPath(targetTryDepth)
|
val relativeFinallyPath = relativeFinallyPath(targetTryDepth)
|
||||||
@@ -216,7 +216,7 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
|||||||
if (fullPath.size > 1) {
|
if (fullPath.size > 1) {
|
||||||
currentStatements += updateFinallyPath(fullPath.drop(1))
|
currentStatements += updateFinallyPath(fullPath.drop(1))
|
||||||
}
|
}
|
||||||
currentStatements += state(fullPath[0])
|
currentStatements += state(fullPath[0], fromNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitTry(x: JsTry) = splitIfNecessary(x) {
|
override fun visitTry(x: JsTry) = splitIfNecessary(x) {
|
||||||
@@ -231,19 +231,19 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
|||||||
|
|
||||||
val oldCatchBlock = currentCatchBlock
|
val oldCatchBlock = currentCatchBlock
|
||||||
currentCatchBlock = catchBlock
|
currentCatchBlock = catchBlock
|
||||||
currentStatements += exceptionState(catchBlock)
|
currentStatements += exceptionState(catchBlock, x)
|
||||||
|
|
||||||
x.tryBlock.statements.forEach { it.accept(this) }
|
x.tryBlock.statements.forEach { it.accept(this) }
|
||||||
|
|
||||||
currentStatements += exceptionState(oldCatchBlock)
|
currentStatements += exceptionState(oldCatchBlock, x)
|
||||||
currentCatchBlock = oldCatchBlock
|
currentCatchBlock = oldCatchBlock
|
||||||
|
|
||||||
if (finallyNode != null) {
|
if (finallyNode != null) {
|
||||||
currentStatements += updateFinallyPath(listOf(successor))
|
currentStatements += updateFinallyPath(listOf(successor))
|
||||||
currentStatements += stateAndJump(finallyBlock)
|
currentStatements += stateAndJump(finallyBlock, x)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
currentStatements += stateAndJump(successor)
|
currentStatements += stateAndJump(successor, x)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle catch node
|
// Handle catch node
|
||||||
@@ -251,10 +251,10 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
|||||||
|
|
||||||
if (finallyNode != null) {
|
if (finallyNode != null) {
|
||||||
currentStatements += updateFinallyPath(listOf(oldCatchBlock))
|
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 {
|
else {
|
||||||
currentStatements += if (catchNode != null) exceptionState(oldCatchBlock) else stateAndJump(oldCatchBlock)
|
currentStatements += if (catchNode != null) exceptionState(oldCatchBlock, x) else stateAndJump(oldCatchBlock, x)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (catchNode != null) {
|
if (catchNode != null) {
|
||||||
@@ -263,11 +263,11 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
|||||||
catchNode.body.statements.forEach { it.accept(this) }
|
catchNode.body.statements.forEach { it.accept(this) }
|
||||||
|
|
||||||
if (finallyNode == null) {
|
if (finallyNode == null) {
|
||||||
currentStatements += stateAndJump(successor)
|
currentStatements += stateAndJump(successor, x)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
currentStatements += updateFinallyPath(listOf(successor))
|
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()
|
val isInFinally = hasEnclosingFinallyBlock()
|
||||||
if (isInFinally) {
|
if (isInFinally) {
|
||||||
val returnBlock = CoroutineBlock()
|
val returnBlock = CoroutineBlock()
|
||||||
jumpWithFinally(0, returnBlock)
|
jumpWithFinally(0, returnBlock, x)
|
||||||
val returnExpression = x.expression
|
val returnExpression = x.expression
|
||||||
val returnFieldRef = if (returnExpression != null) {
|
val returnFieldRef = if (returnExpression != null) {
|
||||||
val ref = JsNameRef(context.returnValueFieldName, JsAstUtils.stateMachineReceiver())
|
val ref = JsNameRef(context.returnValueFieldName, JsAstUtils.stateMachineReceiver())
|
||||||
@@ -343,47 +343,51 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte
|
|||||||
if (assignment != null) {
|
if (assignment != null) {
|
||||||
val rhs = assignment.second
|
val rhs = assignment.second
|
||||||
if (rhs.isSuspend) {
|
if (rhs.isSuspend) {
|
||||||
handleSuspend(expression)
|
handleSuspend(expression, rhs)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (expression.isSuspend) {
|
else if (expression.isSuspend) {
|
||||||
handleSuspend(expression)
|
handleSuspend(expression, expression)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return expression
|
return expression
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSuspend(invocation: JsExpression) {
|
private fun handleSuspend(invocation: JsExpression, sourceNode: JsExpression) {
|
||||||
|
val psi = sourceNode.source ?: invocation.source
|
||||||
|
|
||||||
val nextBlock = CoroutineBlock()
|
val nextBlock = CoroutineBlock()
|
||||||
currentStatements += state(nextBlock)
|
currentStatements += state(nextBlock, invocation)
|
||||||
|
|
||||||
val resultRef = JsNameRef(context.metadata.resultName, JsAstUtils.stateMachineReceiver()).apply {
|
val resultRef = JsNameRef(context.metadata.resultName, JsAstUtils.stateMachineReceiver()).apply {
|
||||||
sideEffects = SideEffectKind.DEPENDS_ON_STATE
|
sideEffects = SideEffectKind.DEPENDS_ON_STATE
|
||||||
}
|
}
|
||||||
val invocationStatement = JsAstUtils.assignment(resultRef, invocation).makeStmt()
|
val invocationStatement = JsAstUtils.assignment(resultRef, invocation).makeStmt()
|
||||||
val suspendCondition = JsAstUtils.equality(resultRef.deepCopy(), context.metadata.suspendObjectRef.deepCopy())
|
val suspendCondition = JsAstUtils.equality(resultRef.deepCopy(), context.metadata.suspendObjectRef.deepCopy()).source(psi)
|
||||||
val suspendIfNeeded = JsIf(suspendCondition, JsReturn(context.metadata.suspendObjectRef.deepCopy()))
|
val suspendIfNeeded = JsIf(suspendCondition, JsReturn(context.metadata.suspendObjectRef.deepCopy().source(psi)))
|
||||||
currentStatements += listOf(invocationStatement, suspendIfNeeded, JsBreak())
|
currentStatements += listOf(invocationStatement, suspendIfNeeded, JsBreak().apply { source = psi })
|
||||||
currentBlock = nextBlock
|
currentBlock = nextBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun state(target: CoroutineBlock): List<JsStatement> {
|
private fun state(target: CoroutineBlock, fromExpression: JsNode): List<JsStatement> {
|
||||||
val placeholder = JsDebugger()
|
val placeholder = JsDebugger()
|
||||||
placeholder.targetBlock = target
|
placeholder.targetBlock = target
|
||||||
|
placeholder.source = fromExpression.source
|
||||||
|
|
||||||
return listOf(placeholder)
|
return listOf(placeholder)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun jump() = JsContinue()
|
private fun jump() = JsContinue()
|
||||||
|
|
||||||
private fun stateAndJump(target: CoroutineBlock): List<JsStatement> {
|
private fun stateAndJump(target: CoroutineBlock, fromNode: JsNode): List<JsStatement> {
|
||||||
return state(target) + jump()
|
return state(target, fromNode) + jump()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun exceptionState(target: CoroutineBlock): List<JsStatement> {
|
private fun exceptionState(target: CoroutineBlock, fromNode: JsNode): List<JsStatement> {
|
||||||
val placeholder = JsDebugger()
|
val placeholder = JsDebugger()
|
||||||
placeholder.targetExceptionBlock = target
|
placeholder.targetExceptionBlock = target
|
||||||
|
placeholder.source = fromNode
|
||||||
|
|
||||||
return listOf(placeholder)
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.js.coroutine
|
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.*
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.coroutineMetadata
|
import org.jetbrains.kotlin.js.backend.ast.metadata.coroutineMetadata
|
||||||
import org.jetbrains.kotlin.js.inline.clean.FunctionPostProcessor
|
import org.jetbrains.kotlin.js.inline.clean.FunctionPostProcessor
|
||||||
@@ -57,6 +58,8 @@ class CoroutineFunctionTransformer(private val program: JsProgram, private val f
|
|||||||
statements: MutableList<JsStatement>,
|
statements: MutableList<JsStatement>,
|
||||||
globalCatchBlockIndex: Int
|
globalCatchBlockIndex: Int
|
||||||
) {
|
) {
|
||||||
|
val psiElement = context.metadata.psiElement
|
||||||
|
|
||||||
val constructor = JsFunction(function.scope.parent, JsBlock(), "Continuation")
|
val constructor = JsFunction(function.scope.parent, JsBlock(), "Continuation")
|
||||||
constructor.name = className
|
constructor.name = className
|
||||||
if (context.metadata.hasReceiver) {
|
if (context.metadata.hasReceiver) {
|
||||||
@@ -80,17 +83,17 @@ class CoroutineFunctionTransformer(private val program: JsProgram, private val f
|
|||||||
|
|
||||||
constructor.body.statements.run {
|
constructor.body.statements.run {
|
||||||
val baseClass = context.metadata.baseClassRef.deepCopy()
|
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) {
|
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) {
|
if (context.metadata.hasReceiver) {
|
||||||
assignToField(context.receiverFieldName, context.receiverFieldName.makeRef())
|
assignToField(context.receiverFieldName, context.receiverFieldName.makeRef(), psiElement)
|
||||||
}
|
}
|
||||||
for (localVariable in localVariables) {
|
for (localVariable in localVariables) {
|
||||||
val value = if (localVariable !in parameterNames) Namer.getUndefinedExpression() else localVariable.makeRef()
|
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) {
|
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) {
|
if (context.metadata.hasReceiver) {
|
||||||
instantiation.arguments += JsLiteral.THIS
|
instantiation.arguments += JsLiteral.THIS
|
||||||
}
|
}
|
||||||
@@ -163,9 +167,13 @@ class CoroutineFunctionTransformer(private val program: JsProgram, private val f
|
|||||||
val instanceName = JsScope.declareTemporaryName("instance")
|
val instanceName = JsScope.declareTemporaryName("instance")
|
||||||
functionWithBody.body.statements += JsAstUtils.newVar(instanceName, instantiation)
|
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(
|
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) {
|
private fun MutableList<JsStatement>.assignToField(fieldName: JsName, value: JsExpression, psiElement: PsiElement?) {
|
||||||
this += JsAstUtils.assignment(JsNameRef(fieldName, JsLiteral.THIS), value).makeStmt()
|
this += JsAstUtils.assignment(JsNameRef(fieldName, JsLiteral.THIS), value).source(psiElement).makeStmt()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun MutableList<JsStatement>.assignToPrototype(fieldName: JsName, value: JsExpression) {
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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) {
|
if (target != null) {
|
||||||
val lhs = JsNameRef(context.metadata.stateName, JsAstUtils.stateMachineReceiver())
|
val lhs = JsNameRef(context.metadata.stateName, JsAstUtils.stateMachineReceiver())
|
||||||
val rhs = program.getNumberLiteral(blockIndexes[target]!!)
|
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
|
targetBlock = true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,7 @@ fun List<CoroutineBlock>.replaceCoroutineFlowStatements(context: CoroutineTransf
|
|||||||
if (exceptionTarget != null) {
|
if (exceptionTarget != null) {
|
||||||
val lhs = JsNameRef(context.metadata.exceptionStateName, JsAstUtils.stateMachineReceiver())
|
val lhs = JsNameRef(context.metadata.exceptionStateName, JsAstUtils.stateMachineReceiver())
|
||||||
val rhs = program.getNumberLiteral(blockIndexes[exceptionTarget]!!)
|
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
|
targetExceptionBlock = true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -141,7 +141,7 @@ fun List<CoroutineBlock>.replaceCoroutineFlowStatements(context: CoroutineTransf
|
|||||||
if (finallyPath.isNotEmpty()) {
|
if (finallyPath.isNotEmpty()) {
|
||||||
val lhs = JsNameRef(context.metadata.finallyPathName, JsAstUtils.stateMachineReceiver())
|
val lhs = JsNameRef(context.metadata.finallyPathName, JsAstUtils.stateMachineReceiver())
|
||||||
val rhs = JsArrayLiteral(finallyPath.map { program.getNumberLiteral(blockIndexes[it]!!) })
|
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
|
this.finallyPath = true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -222,12 +222,14 @@ fun JsBlock.replaceSpecialReferences(context: CoroutineTransformationContext) {
|
|||||||
|
|
||||||
x.coroutineController -> {
|
x.coroutineController -> {
|
||||||
ctx.replaceMe(JsNameRef(context.controllerFieldName, x.qualifier).apply {
|
ctx.replaceMe(JsNameRef(context.controllerFieldName, x.qualifier).apply {
|
||||||
|
source = x.source
|
||||||
sideEffects = SideEffectKind.PURE
|
sideEffects = SideEffectKind.PURE
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
x.coroutineResult -> {
|
x.coroutineResult -> {
|
||||||
ctx.replaceMe(JsNameRef(context.metadata.resultName, x.qualifier).apply {
|
ctx.replaceMe(JsNameRef(context.metadata.resultName, x.qualifier).apply {
|
||||||
|
source = x.source
|
||||||
sideEffects = SideEffectKind.DEPENDS_ON_STATE
|
sideEffects = SideEffectKind.DEPENDS_ON_STATE
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -262,7 +264,7 @@ fun JsBlock.replaceLocalVariables(context: CoroutineTransformationContext, local
|
|||||||
override fun endVisit(x: JsNameRef, ctx: JsContext<in JsNode>) {
|
override fun endVisit(x: JsNameRef, ctx: JsContext<in JsNode>) {
|
||||||
if (x.qualifier == null && x.name in localVariables) {
|
if (x.qualifier == null && x.name in localVariables) {
|
||||||
val fieldName = context.getFieldName(x.name!!)
|
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);
|
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")
|
@TestMetadata("inlining.kt")
|
||||||
public void testInlining() throws Exception {
|
public void testInlining() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/inlining.kt");
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 (resolvedCall.resultingDescriptor.isSuspend) {
|
||||||
if (context.isInStateMachine) {
|
if (context.isInStateMachine) {
|
||||||
context.currentBlock.statements += JsAstUtils.asSyntheticStatement(callExpression.apply { isSuspend = true })
|
context.currentBlock.statements += JsAstUtils.asSyntheticStatement(callExpression.apply {
|
||||||
val coroutineRef = TranslationUtils.translateContinuationArgument(context)
|
isSuspend = true
|
||||||
|
source = resolvedCall.call.callElement
|
||||||
|
})
|
||||||
|
val coroutineRef = TranslationUtils.translateContinuationArgument(context).apply { source = resolvedCall.call.callElement }
|
||||||
return context.defineTemporary(JsNameRef("\$\$coroutineResult\$\$", coroutineRef).apply {
|
return context.defineTemporary(JsNameRef("\$\$coroutineResult\$\$", coroutineRef).apply {
|
||||||
sideEffects = SideEffectKind.DEPENDS_ON_STATE
|
sideEffects = SideEffectKind.DEPENDS_ON_STATE
|
||||||
|
source = resolvedCall.call.callElement
|
||||||
coroutineResult = true
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasOrInheritsParametersWithDefaultValue
|
import org.jetbrains.kotlin.resolve.descriptorUtil.hasOrInheritsParametersWithDefaultValue
|
||||||
|
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
fun generateDelegateCall(
|
fun generateDelegateCall(
|
||||||
@@ -184,6 +185,7 @@ fun JsFunction.fillCoroutineMetadata(
|
|||||||
resultName = getCoroutinePropertyName("result"),
|
resultName = getCoroutinePropertyName("result"),
|
||||||
exceptionName = getCoroutinePropertyName("exception"),
|
exceptionName = getCoroutinePropertyName("exception"),
|
||||||
hasController = hasController,
|
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