Make stack values for assignment-like operations lazy
As well as for other kinds of expressions Within attached test they were generated twice in case of last expression of coroutine block, because coroutine related codegen part is built upon assumption that all expressions should be generated lazily Also add a test about unary postfix increment/decrement #KT-13156 Fixed
This commit is contained in:
@@ -3590,30 +3590,41 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
return StackValue.cmp(expression.getOperationToken(), type, leftValue, rightValue);
|
return StackValue.cmp(expression.getOperationToken(), type, leftValue, rightValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private StackValue generateAssignmentExpression(KtBinaryExpression expression) {
|
private StackValue generateAssignmentExpression(final KtBinaryExpression expression) {
|
||||||
StackValue stackValue = gen(expression.getLeft());
|
return StackValue.operation(Type.VOID_TYPE, new Function1<InstructionAdapter, Unit>() {
|
||||||
KtExpression right = expression.getRight();
|
@Override
|
||||||
assert right != null : expression.getText();
|
public Unit invoke(InstructionAdapter adapter) {
|
||||||
stackValue.store(gen(right), v);
|
StackValue stackValue = gen(expression.getLeft());
|
||||||
return StackValue.none();
|
KtExpression right = expression.getRight();
|
||||||
|
assert right != null : expression.getText();
|
||||||
|
stackValue.store(gen(right), v);
|
||||||
|
|
||||||
|
return Unit.INSTANCE;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private StackValue generateAugmentedAssignment(KtBinaryExpression expression) {
|
private StackValue generateAugmentedAssignment(final KtBinaryExpression expression) {
|
||||||
ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext);
|
return StackValue.operation(Type.VOID_TYPE, new Function1<InstructionAdapter, Unit>() {
|
||||||
FunctionDescriptor descriptor = accessibleFunctionDescriptor(resolvedCall);
|
@Override
|
||||||
Callable callable = resolveToCallable(descriptor, false, resolvedCall);
|
public Unit invoke(InstructionAdapter adapter) {
|
||||||
KtExpression lhs = expression.getLeft();
|
ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext);
|
||||||
Type lhsType = expressionType(lhs);
|
FunctionDescriptor descriptor = accessibleFunctionDescriptor(resolvedCall);
|
||||||
|
Callable callable = resolveToCallable(descriptor, false, resolvedCall);
|
||||||
|
KtExpression lhs = expression.getLeft();
|
||||||
|
Type lhsType = expressionType(lhs);
|
||||||
|
|
||||||
boolean keepReturnValue = Boolean.TRUE.equals(bindingContext.get(VARIABLE_REASSIGNMENT, expression))
|
boolean keepReturnValue = Boolean.TRUE.equals(bindingContext.get(VARIABLE_REASSIGNMENT, expression))
|
||||||
|| !KotlinBuiltIns.isUnit(descriptor.getReturnType());
|
|| !KotlinBuiltIns.isUnit(descriptor.getReturnType());
|
||||||
|
|
||||||
callAugAssignMethod(expression, resolvedCall, callable, lhsType, keepReturnValue);
|
putCallAugAssignMethod(expression, resolvedCall, callable, lhsType, keepReturnValue);
|
||||||
|
|
||||||
return StackValue.none();
|
return Unit.INSTANCE;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void callAugAssignMethod(
|
private void putCallAugAssignMethod(
|
||||||
@NotNull KtBinaryExpression expression,
|
@NotNull KtBinaryExpression expression,
|
||||||
@NotNull ResolvedCall<?> resolvedCall,
|
@NotNull ResolvedCall<?> resolvedCall,
|
||||||
@NotNull Callable callable,
|
@NotNull Callable callable,
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
class Controller {
|
||||||
|
var wasHandleResultCalled = false
|
||||||
|
suspend fun suspendHere(x: Continuation<String>) {
|
||||||
|
x.resume("OK")
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun handleResult(x: Unit, y: Continuation<Nothing>) {
|
||||||
|
wasHandleResultCalled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||||
|
val controller = Controller()
|
||||||
|
c(controller).resume(Unit)
|
||||||
|
|
||||||
|
if (!controller.wasHandleResultCalled) throw java.lang.RuntimeException("fail 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var result = 0
|
||||||
|
|
||||||
|
builder {
|
||||||
|
result++
|
||||||
|
|
||||||
|
if (suspendHere() != "OK") throw java.lang.RuntimeException("fail 2")
|
||||||
|
|
||||||
|
result--
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != 0) return "fail 3"
|
||||||
|
|
||||||
|
builder {
|
||||||
|
--result
|
||||||
|
|
||||||
|
if (suspendHere() != "OK") throw java.lang.RuntimeException("fail 4")
|
||||||
|
|
||||||
|
++result
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != 0) return "fail 5"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
class Controller {
|
||||||
|
var wasHandleResultCalled = false
|
||||||
|
suspend fun suspendHere(x: Continuation<String>) {
|
||||||
|
x.resume("OK")
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun handleResult(x: Unit, y: Continuation<Nothing>) {
|
||||||
|
wasHandleResultCalled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||||
|
val controller = Controller()
|
||||||
|
c(controller).resume(Unit)
|
||||||
|
|
||||||
|
if (!controller.wasHandleResultCalled) throw java.lang.RuntimeException("fail 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
var varWithCustomSetter: String = ""
|
||||||
|
set(value) {
|
||||||
|
if (field != "") throw java.lang.RuntimeException("fail 2")
|
||||||
|
field = value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var result = ""
|
||||||
|
|
||||||
|
builder {
|
||||||
|
result += "O"
|
||||||
|
|
||||||
|
if (suspendHere() != "OK") throw java.lang.RuntimeException("fail 3")
|
||||||
|
|
||||||
|
result += "K"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != "OK") return "fail 4"
|
||||||
|
|
||||||
|
builder {
|
||||||
|
if (suspendHere() != "OK") throw java.lang.RuntimeException("fail 5")
|
||||||
|
|
||||||
|
varWithCustomSetter = "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
return varWithCustomSetter
|
||||||
|
}
|
||||||
@@ -4285,6 +4285,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("lastStatementInc.kt")
|
||||||
|
public void testLastStatementInc() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastStatementInc.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("lastStementAssignment.kt")
|
||||||
|
public void testLastStementAssignment() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastStementAssignment.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("lastUnitExpression.kt")
|
@TestMetadata("lastUnitExpression.kt")
|
||||||
public void testLastUnitExpression() throws Exception {
|
public void testLastUnitExpression() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastUnitExpression.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastUnitExpression.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user