JS: fix destructuring declaration and increment in coroutines. See KT-16058

This commit is contained in:
Alexey Andreev
2017-01-31 15:22:43 +03:00
parent b929db1b07
commit 97b6c3013a
10 changed files with 74 additions and 36 deletions
@@ -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
}
@@ -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"
@@ -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
@@ -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")
@@ -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
}
}
@@ -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);
}
@@ -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);
@@ -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);
}
}
@@ -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);
}
}