JS: fix translation of for statement when either next or hasNext method translates to multiple statements. Fix KT-15367
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// WITH_COROUTINES
|
// WITH_COROUTINES
|
||||||
// TARGET_BACKEND: JVM
|
|
||||||
import kotlin.coroutines.*
|
import kotlin.coroutines.*
|
||||||
|
|
||||||
interface AsyncGenerator<in T> {
|
interface AsyncGenerator<in T> {
|
||||||
|
|||||||
@@ -5298,6 +5298,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("asyncIterator.kt")
|
||||||
|
public void testAsyncIterator() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/asyncIterator.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("await.kt")
|
@TestMetadata("await.kt")
|
||||||
public void testAwait() throws Exception {
|
public void testAwait() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/await.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/await.kt");
|
||||||
|
|||||||
+26
-8
@@ -179,25 +179,43 @@ fun translateForExpression(expression: KtForExpression, context: TranslationCont
|
|||||||
|
|
||||||
fun translateForOverIterator(): JsStatement {
|
fun translateForOverIterator(): JsStatement {
|
||||||
|
|
||||||
fun translateMethodInvocation(receiver: JsExpression?, resolvedCall: ResolvedCall<FunctionDescriptor>): JsExpression =
|
fun translateMethodInvocation(
|
||||||
CallTranslator.translate(context, resolvedCall, receiver)
|
receiver: JsExpression?,
|
||||||
|
resolvedCall: ResolvedCall<FunctionDescriptor>,
|
||||||
|
block: JsBlock
|
||||||
|
): JsExpression = CallTranslator.translate(context.innerBlock(block), resolvedCall, receiver)
|
||||||
|
|
||||||
fun iteratorMethodInvocation(): JsExpression {
|
fun iteratorMethodInvocation(): JsExpression {
|
||||||
val range = Translation.translateAsExpression(loopRange, context)
|
val range = Translation.translateAsExpression(loopRange, context)
|
||||||
val resolvedCall = getIteratorFunction(context.bindingContext(), loopRange)
|
val resolvedCall = getIteratorFunction(context.bindingContext(), loopRange)
|
||||||
return translateMethodInvocation(range, resolvedCall)
|
return CallTranslator.translate(context, resolvedCall, range)
|
||||||
}
|
}
|
||||||
|
|
||||||
val iteratorVar = context.defineTemporary(iteratorMethodInvocation())
|
val iteratorVar = context.defineTemporary(iteratorMethodInvocation())
|
||||||
|
|
||||||
fun hasNextMethodInvocation(): JsExpression {
|
fun hasNextMethodInvocation(block: JsBlock): JsExpression {
|
||||||
val resolvedCall = getHasNextCallable(context.bindingContext(), loopRange)
|
val resolvedCall = getHasNextCallable(context.bindingContext(), loopRange)
|
||||||
return translateMethodInvocation(iteratorVar, resolvedCall)
|
return translateMethodInvocation(iteratorVar, resolvedCall, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
val nextInvoke = translateMethodInvocation(iteratorVar, getNextFunction(context.bindingContext(), loopRange))
|
val hasNextBlock = JsBlock()
|
||||||
val body = translateBody(nextInvoke)
|
val hasNextInvocation = hasNextMethodInvocation(hasNextBlock)
|
||||||
return JsWhile(hasNextMethodInvocation(), body ?: nextInvoke.makeStmt())
|
|
||||||
|
val nextBlock = JsBlock()
|
||||||
|
val nextInvoke = translateMethodInvocation(iteratorVar, getNextFunction(context.bindingContext(), loopRange), nextBlock)
|
||||||
|
|
||||||
|
val bodyStatements = mutableListOf<JsStatement>()
|
||||||
|
val exitCondition = if (hasNextBlock.isEmpty) {
|
||||||
|
hasNextInvocation
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bodyStatements += hasNextBlock.statements
|
||||||
|
bodyStatements += JsIf(notOptimized(hasNextInvocation), JsBreak())
|
||||||
|
JsLiteral.TRUE
|
||||||
|
}
|
||||||
|
bodyStatements += nextBlock.statements
|
||||||
|
bodyStatements += translateBody(nextInvoke)?.let(::flattenStatement).orEmpty()
|
||||||
|
return JsWhile(exitCondition, bodyStatements.singleOrNull() ?: JsBlock(bodyStatements))
|
||||||
}
|
}
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
|
|||||||
Reference in New Issue
Block a user