JS: fix destructuring declaration and increment in coroutines. See KT-16058
This commit is contained in:
+31
@@ -0,0 +1,31 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
|
||||
// TARGET_BACKEND: JS
|
||||
// TODO: looks like this is a bug in JVM backend
|
||||
import kotlin.coroutines.experimental.*
|
||||
import kotlin.coroutines.experimental.intrinsics.*
|
||||
|
||||
suspend fun suspendThere(v: A): A = suspendCoroutineOrReturn { x ->
|
||||
x.resume(v)
|
||||
COROUTINE_SUSPENDED
|
||||
}
|
||||
|
||||
class A(val value: String) {
|
||||
operator suspend fun plus(other: A) = suspendThere(A(value + other.value))
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
|
||||
fun box(): String {
|
||||
var a = A("O")
|
||||
|
||||
builder {
|
||||
a += A("K")
|
||||
}
|
||||
|
||||
return a.value
|
||||
}
|
||||
+9
-3
@@ -1,6 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// IGNORE_BACKEND: JS
|
||||
import kotlin.coroutines.experimental.*
|
||||
import kotlin.coroutines.experimental.intrinsics.*
|
||||
import kotlin.reflect.KProperty
|
||||
@@ -34,7 +33,7 @@ class A(val x: String) {
|
||||
operator suspend fun unaryPlus() = suspendThere(x + "K")
|
||||
|
||||
operator suspend fun inc(): A = suspendCoroutineOrReturn { x ->
|
||||
isProvideDelegateCalled = true
|
||||
isIncCalled = true
|
||||
x.resume(this)
|
||||
COROUTINE_SUSPENDED
|
||||
}
|
||||
@@ -86,7 +85,13 @@ suspend fun foo4() {
|
||||
|
||||
suspend fun foo6() {
|
||||
var y = a++
|
||||
if (y.isIncCalled) throw RuntimeException("fail 7")
|
||||
if (!y.isIncCalled) throw RuntimeException("fail 7")
|
||||
}
|
||||
|
||||
suspend fun foo7() {
|
||||
a.isIncCalled = false
|
||||
val y = ++a
|
||||
if (!y.isIncCalled) throw RuntimeException("fail 8")
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
@@ -98,6 +103,7 @@ fun box(): String {
|
||||
foo4()
|
||||
//foo5()
|
||||
foo6()
|
||||
foo7()
|
||||
}
|
||||
|
||||
return "OK"
|
||||
|
||||
Vendored
+1
@@ -60,6 +60,7 @@ public final class OperatorsKt {
|
||||
public final static @org.jetbrains.annotations.Nullable method foo3(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method foo4(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method foo6(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method foo7(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.NotNull method getA(): A
|
||||
public final static method setA(@org.jetbrains.annotations.NotNull p0: A): void
|
||||
public final static @org.jetbrains.annotations.Nullable method suspendThere(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||
|
||||
+7
-7
@@ -5891,6 +5891,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@TestMetadata("augmentedAssignment.kt")
|
||||
public void testAugmentedAssignment() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/augmentedAssignment.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dispatchResume.kt")
|
||||
public void testDispatchResume() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/dispatchResume.kt");
|
||||
@@ -5930,13 +5936,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
@TestMetadata("operators.kt")
|
||||
public void testOperators() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/operators.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("privateFunctions.kt")
|
||||
|
||||
+5
-5
@@ -77,18 +77,18 @@ public class DestructuringDeclarationTranslator extends AbstractTranslator {
|
||||
}
|
||||
|
||||
private JsVars translate() {
|
||||
List<JsVars.JsVar> jsVars = new ArrayList<JsVars.JsVar>();
|
||||
if (initializer != null) {
|
||||
jsVars.add(new JsVars.JsVar(multiObjectName, initializer));
|
||||
context().getCurrentBlock().getStatements().add(JsAstUtils.newVar(multiObjectName, initializer));
|
||||
}
|
||||
|
||||
List<JsVars.JsVar> jsVars = new ArrayList<JsVars.JsVar>();
|
||||
JsNameRef multiObjNameRef = multiObjectName.makeRef();
|
||||
for (KtDestructuringDeclarationEntry entry : multiDeclaration.getEntries()) {
|
||||
VariableDescriptor descriptor = BindingContextUtils.getNotNull( context().bindingContext(), BindingContext.VARIABLE, entry);
|
||||
VariableDescriptor descriptor = BindingContextUtils.getNotNull(context().bindingContext(), BindingContext.VARIABLE, entry);
|
||||
// Do not call `componentX` for destructuring entry called _
|
||||
if (descriptor.getName().isSpecial()) continue;
|
||||
|
||||
ResolvedCall<FunctionDescriptor> entryInitCall = context().bindingContext().get(BindingContext.COMPONENT_RESOLVED_CALL, entry);
|
||||
ResolvedCall<FunctionDescriptor> entryInitCall = context().bindingContext().get(BindingContext.COMPONENT_RESOLVED_CALL, entry);
|
||||
assert entryInitCall != null : "Entry init call must be not null";
|
||||
JsExpression entryInitializer = CallTranslator.translate(context(), entryInitCall, multiObjNameRef);
|
||||
FunctionDescriptor candidateDescriptor = entryInitCall.getCandidateDescriptor();
|
||||
@@ -101,7 +101,7 @@ public class DestructuringDeclarationTranslator extends AbstractTranslator {
|
||||
entryInitializer = JsAstUtils.charToBoxedChar(entryInitializer);
|
||||
}
|
||||
|
||||
JsName name = context().getNameForDescriptor(descriptor);
|
||||
JsName name = context().getNameForDescriptor(descriptor);
|
||||
if (isVarCapturedInClosure(context().bindingContext(), descriptor)) {
|
||||
JsNameRef alias = getCapturedVarAccessor(name.makeRef());
|
||||
entryInitializer = JsAstUtils.wrapValue(alias, entryInitializer);
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.psi.KtWhileExpressionBase
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
|
||||
fun createWhile(doWhile: Boolean, expression: KtWhileExpressionBase, context: TranslationContext): JsNode {
|
||||
val conditionExpression = expression.condition ?:
|
||||
@@ -89,13 +90,13 @@ fun translateForExpression(expression: KtForExpression, context: TranslationCont
|
||||
fun isForOverRangeLiteral(): Boolean =
|
||||
loopRange is KtBinaryExpression && loopRange.operationToken == KtTokens.RANGE && isForOverRange()
|
||||
|
||||
fun isForOverArray(): Boolean {
|
||||
fun isForOverArray(): Boolean {
|
||||
return KotlinBuiltIns.isArray(rangeType) || KotlinBuiltIns.isPrimitiveArray(rangeType)
|
||||
}
|
||||
|
||||
|
||||
val loopParameter = expression.loopParameter!!
|
||||
val destructuringParameter: KtDestructuringDeclaration? = loopParameter?.destructuringDeclaration
|
||||
val destructuringParameter: KtDestructuringDeclaration? = loopParameter.destructuringDeclaration
|
||||
val parameterName = if (destructuringParameter == null) {
|
||||
context.getNameForElement(loopParameter)
|
||||
}
|
||||
@@ -109,18 +110,19 @@ fun translateForExpression(expression: KtForExpression, context: TranslationCont
|
||||
return realBody
|
||||
}
|
||||
else {
|
||||
val block = JsBlock()
|
||||
|
||||
val currentVarInit =
|
||||
if (destructuringParameter == null) {
|
||||
newVar(parameterName, itemValue)
|
||||
}
|
||||
else {
|
||||
DestructuringDeclarationTranslator.translate(destructuringParameter, parameterName, itemValue, context)
|
||||
DestructuringDeclarationTranslator.translate(
|
||||
destructuringParameter, parameterName, itemValue, context.innerBlock(block))
|
||||
}
|
||||
block.statements += currentVarInit
|
||||
block.statements += if (realBody is JsBlock) realBody.statements else realBody.singletonOrEmptyList()
|
||||
|
||||
if (realBody == null) return JsBlock(currentVarInit)
|
||||
|
||||
val block = convertToBlock(realBody)
|
||||
block.statements.add(0, currentVarInit)
|
||||
return block
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ public class DynamicIncrementTranslator extends IncrementTranslator {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected JsExpression operationExpression(@NotNull JsExpression receiver) {
|
||||
protected JsExpression operationExpression(@NotNull TranslationContext context, @NotNull JsExpression receiver) {
|
||||
return unaryAsBinary(receiver);
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -91,7 +91,7 @@ public abstract class IncrementTranslator extends AbstractTranslator {
|
||||
// code fragment: expr(a++)
|
||||
// generate: expr(a = a.inc(), a)
|
||||
JsExpression getExpression = accessTranslator.translateAsGet();
|
||||
JsExpression reassignment = variableReassignment(getExpression);
|
||||
JsExpression reassignment = variableReassignment(context().innerBlock(accessBlock), getExpression);
|
||||
accessBlock.getStatements().add(JsAstUtils.asSyntheticStatement(reassignment));
|
||||
JsExpression getNewValue = accessTranslator.translateAsGet();
|
||||
|
||||
@@ -114,7 +114,7 @@ public abstract class IncrementTranslator extends AbstractTranslator {
|
||||
// generate: expr( (t1 = a, t2 = t1, a = t1.inc(), t2) )
|
||||
TemporaryVariable t1 = context().declareTemporary(accessTranslator.translateAsGet());
|
||||
accessBlock.getStatements().add(t1.assignmentStatement());
|
||||
JsExpression variableReassignment = variableReassignment(t1.reference());
|
||||
JsExpression variableReassignment = variableReassignment(context().innerBlock(accessBlock), t1.reference());
|
||||
accessBlock.getStatements().add(JsAstUtils.asSyntheticStatement(variableReassignment));
|
||||
|
||||
JsExpression result;
|
||||
@@ -131,13 +131,13 @@ public abstract class IncrementTranslator extends AbstractTranslator {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression variableReassignment(@NotNull JsExpression toCallMethodUpon) {
|
||||
JsExpression overloadedMethodCallOnPropertyGetter = operationExpression(toCallMethodUpon);
|
||||
private JsExpression variableReassignment(@NotNull TranslationContext context, @NotNull JsExpression toCallMethodUpon) {
|
||||
JsExpression overloadedMethodCallOnPropertyGetter = operationExpression(context, toCallMethodUpon);
|
||||
return accessTranslator.translateAsSet(overloadedMethodCallOnPropertyGetter);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
abstract JsExpression operationExpression(@NotNull JsExpression receiver);
|
||||
abstract JsExpression operationExpression(@NotNull TranslationContext context, @NotNull JsExpression receiver);
|
||||
|
||||
private static boolean isDynamic(TranslationContext context, KtUnaryExpression expression) {
|
||||
CallableDescriptor operationDescriptor = getCallableDescriptorForOperationExpression(context.bindingContext(), expression);
|
||||
|
||||
+4
-4
@@ -41,9 +41,9 @@ public final class IntrinsicIncrementTranslator extends IncrementTranslator {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected JsExpression operationExpression(@NotNull JsExpression receiver) {
|
||||
FunctionIntrinsic intrinsic = context().intrinsics().getFunctionIntrinsic(resolvedCall.getResultingDescriptor());
|
||||
CallInfo callInfo = CallInfoKt.getCallInfo(context(), resolvedCall, receiver);
|
||||
return intrinsic.apply(callInfo, Collections.<JsExpression>emptyList(), context());
|
||||
protected JsExpression operationExpression(@NotNull TranslationContext context, @NotNull JsExpression receiver) {
|
||||
FunctionIntrinsic intrinsic = context.intrinsics().getFunctionIntrinsic(resolvedCall.getResultingDescriptor());
|
||||
CallInfo callInfo = CallInfoKt.getCallInfo(context, resolvedCall, receiver);
|
||||
return intrinsic.apply(callInfo, Collections.<JsExpression>emptyList(), context);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-4
@@ -38,11 +38,9 @@ public final class OverloadedIncrementTranslator extends IncrementTranslator {
|
||||
this.resolvedCall = CallUtilKt.getFunctionResolvedCallWithAssert(expression, context.bindingContext());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected JsExpression operationExpression(@NotNull JsExpression receiver) {
|
||||
return CallTranslator.translate(context(), resolvedCall, receiver);
|
||||
protected JsExpression operationExpression(@NotNull TranslationContext context, @NotNull JsExpression receiver) {
|
||||
return CallTranslator.translate(context, resolvedCall, receiver);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user