postfix part of KT-471
This commit is contained in:
@@ -2006,19 +2006,36 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
Arrays.asList(expression.getBaseExpression()), receiver);
|
Arrays.asList(expression.getBaseExpression()), receiver);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return invokeOperation(expression, (FunctionDescriptor) op, (CallableMethod) callable);
|
DeclarationDescriptor cls = op.getContainingDeclaration();
|
||||||
|
if (isNumberPrimitive(cls) || !(op.getName().equals("inc") || op.getName().equals("dec")) ) {
|
||||||
|
return invokeOperation(expression, (FunctionDescriptor) op, (CallableMethod) callable);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
|
||||||
|
assert resolvedCall != null;
|
||||||
|
|
||||||
|
StackValue value = gen(expression.getBaseExpression());
|
||||||
|
value.dupReceiver(v);
|
||||||
|
value.dupReceiver(v);
|
||||||
|
|
||||||
|
Type type = expressionType(expression.getBaseExpression());
|
||||||
|
value.put(type, v);
|
||||||
|
((CallableMethod)callable).invoke(v);
|
||||||
|
value.store(v);
|
||||||
|
value.put(type, v);
|
||||||
|
return StackValue.onStack(type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private StackValue invokeOperation(JetOperationExpression expression, FunctionDescriptor op, CallableMethod callable) {
|
private StackValue invokeOperation(JetOperationExpression expression, FunctionDescriptor op, CallableMethod callable) {
|
||||||
ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
|
ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
|
||||||
assert resolvedCall != null;
|
assert resolvedCall != null;
|
||||||
CallableMethod callableMethod = (CallableMethod) callable;
|
genThisAndReceiverFromResolvedCall(StackValue.none(), resolvedCall, callable);
|
||||||
genThisAndReceiverFromResolvedCall(StackValue.none(), resolvedCall, callableMethod);
|
|
||||||
pushTypeArguments(resolvedCall);
|
pushTypeArguments(resolvedCall);
|
||||||
pushMethodArguments(resolvedCall, callableMethod.getValueParameterTypes());
|
pushMethodArguments(resolvedCall, callable.getValueParameterTypes());
|
||||||
callableMethod.invoke(v);
|
callable.invoke(v);
|
||||||
return returnValueAsStackValue((FunctionDescriptor) op, callableMethod.getSignature().getAsmMethod().getReturnType());
|
return returnValueAsStackValue(op, callable.getSignature().getAsmMethod().getReturnType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -2027,19 +2044,63 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
if (op instanceof FunctionDescriptor) {
|
if (op instanceof FunctionDescriptor) {
|
||||||
final Type asmType = expressionType(expression);
|
final Type asmType = expressionType(expression);
|
||||||
DeclarationDescriptor cls = op.getContainingDeclaration();
|
DeclarationDescriptor cls = op.getContainingDeclaration();
|
||||||
if (isNumberPrimitive(cls) && (op.getName().equals("inc") || op.getName().equals("dec"))) {
|
if (op.getName().equals("inc") || op.getName().equals("dec")) {
|
||||||
receiver.put(receiver.type, v);
|
if (isNumberPrimitive(cls)) {
|
||||||
JetExpression operand = expression.getBaseExpression();
|
receiver.put(receiver.type, v);
|
||||||
if (operand instanceof JetReferenceExpression) {
|
JetExpression operand = expression.getBaseExpression();
|
||||||
final int index = indexOfLocal((JetReferenceExpression) operand);
|
if (operand instanceof JetReferenceExpression) {
|
||||||
if (index >= 0 && isIntPrimitive(asmType)) {
|
final int index = indexOfLocal((JetReferenceExpression) operand);
|
||||||
int increment = op.getName().equals("inc") ? 1 : -1;
|
if (index >= 0 && isIntPrimitive(asmType)) {
|
||||||
return StackValue.postIncrement(index, increment);
|
int increment = op.getName().equals("inc") ? 1 : -1;
|
||||||
|
return StackValue.postIncrement(index, increment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
gen(operand, asmType); // old value
|
||||||
|
generateIncrement(op, asmType, operand, receiver); // increment in-place
|
||||||
|
return StackValue.onStack(asmType); // old value
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
|
||||||
|
assert resolvedCall != null;
|
||||||
|
|
||||||
|
final Callable callable = resolveToCallable(op, false);
|
||||||
|
|
||||||
|
StackValue value = gen(expression.getBaseExpression());
|
||||||
|
value.dupReceiver(v);
|
||||||
|
|
||||||
|
Type type = expressionType(expression.getBaseExpression());
|
||||||
|
value.put(type, v);
|
||||||
|
|
||||||
|
switch(value.receiverSize()) {
|
||||||
|
case 0:
|
||||||
|
if(type.getSize() == 2)
|
||||||
|
v.dup2();
|
||||||
|
else
|
||||||
|
v.dup();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
if(type.getSize() == 2)
|
||||||
|
v.dup2X1();
|
||||||
|
else
|
||||||
|
v.dupX1();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
if(type.getSize() == 2)
|
||||||
|
v.dup2X2();
|
||||||
|
else
|
||||||
|
v.dupX2();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -1:
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
((CallableMethod)callable).invoke(v);
|
||||||
|
value.store(v);
|
||||||
|
return StackValue.onStack(type);
|
||||||
}
|
}
|
||||||
gen(operand, asmType); // old value
|
|
||||||
generateIncrement(op, asmType, operand, receiver); // increment in-place
|
|
||||||
return StackValue.onStack(asmType); // old value
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new UnsupportedOperationException("Don't know how to generate this prefix expression");
|
throw new UnsupportedOperationException("Don't know how to generate this prefix expression");
|
||||||
|
|||||||
@@ -51,6 +51,10 @@ public abstract class StackValue {
|
|||||||
public void dupReceiver(InstructionAdapter v) {
|
public void dupReceiver(InstructionAdapter v) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int receiverSize() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
|
public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
|
||||||
if (this.type == Type.BOOLEAN_TYPE) {
|
if (this.type == Type.BOOLEAN_TYPE) {
|
||||||
put(Type.BOOLEAN_TYPE, v);
|
put(Type.BOOLEAN_TYPE, v);
|
||||||
@@ -491,6 +495,10 @@ public abstract class StackValue {
|
|||||||
public void dupReceiver(InstructionAdapter v) {
|
public void dupReceiver(InstructionAdapter v) {
|
||||||
v.dup2(); // array and index
|
v.dup2(); // array and index
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int receiverSize() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class CollectionElement extends StackValue {
|
private static class CollectionElement extends StackValue {
|
||||||
@@ -547,6 +555,15 @@ public abstract class StackValue {
|
|||||||
((IntrinsicMethod)setter).generate(codegen, v, null, null, null, null);
|
((IntrinsicMethod)setter).generate(codegen, v, null, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int receiverSize() {
|
||||||
|
if(isStandardStack(resolvedGetCall) && isStandardStack(resolvedSetCall)) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dupReceiver(InstructionAdapter v) {
|
public void dupReceiver(InstructionAdapter v) {
|
||||||
if(isStandardStack(resolvedGetCall) && isStandardStack(resolvedSetCall)) {
|
if(isStandardStack(resolvedGetCall) && isStandardStack(resolvedSetCall)) {
|
||||||
@@ -686,6 +703,9 @@ public abstract class StackValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isStandardStack(ResolvedCall call) {
|
private boolean isStandardStack(ResolvedCall call) {
|
||||||
|
if(call == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
for (TypeParameterDescriptor typeParameterDescriptor : call.getResultingDescriptor().getTypeParameters()) {
|
for (TypeParameterDescriptor typeParameterDescriptor : call.getResultingDescriptor().getTypeParameters()) {
|
||||||
if(typeParameterDescriptor.isReified())
|
if(typeParameterDescriptor.isReified())
|
||||||
return false;
|
return false;
|
||||||
@@ -736,6 +756,10 @@ public abstract class StackValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int receiverSize() {
|
||||||
|
return isStatic ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void store(InstructionAdapter v) {
|
public void store(InstructionAdapter v) {
|
||||||
v.visitFieldInsn(isStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD, owner, name, this.type.getDescriptor());
|
v.visitFieldInsn(isStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD, owner, name, this.type.getDescriptor());
|
||||||
@@ -801,6 +825,10 @@ public abstract class StackValue {
|
|||||||
v.dup();
|
v.dup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int receiverSize() {
|
||||||
|
return isStatic ? 0 : 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Expression extends StackValue {
|
private static class Expression extends StackValue {
|
||||||
@@ -904,6 +932,10 @@ public abstract class StackValue {
|
|||||||
v.dup();
|
v.dup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int receiverSize() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void put(Type type, InstructionAdapter v) {
|
public void put(Type type, InstructionAdapter v) {
|
||||||
Type sharedType = sharedTypeForType(this.type);
|
Type sharedType = sharedTypeForType(this.type);
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
class MyNumber(val i: Int) {
|
||||||
|
fun inc(): MyNumber = MyNumber(i+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
class MNR(var ref: MyNumber) {}
|
||||||
|
|
||||||
|
fun test1() : Boolean {
|
||||||
|
var m = MyNumber(42)
|
||||||
|
|
||||||
|
m++
|
||||||
|
if (m.i != 43) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test2() : Boolean {
|
||||||
|
var m = MyNumber(44)
|
||||||
|
|
||||||
|
var m2 = m++
|
||||||
|
if (m2.i != 44) return false
|
||||||
|
if (m.i != 45) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test3() : Boolean {
|
||||||
|
var mnr = MNR(MyNumber(42))
|
||||||
|
mnr.ref++
|
||||||
|
if (mnr.ref.i != 43) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test4() : Boolean {
|
||||||
|
var mnr = MNR(MyNumber(42))
|
||||||
|
val m3 = mnr.ref++
|
||||||
|
if (m3.i != 42) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test5() : Boolean {
|
||||||
|
var mnr = Array<MyNumber>(2,{MyNumber(42)})
|
||||||
|
mnr[0]++
|
||||||
|
if (mnr[0].i != 43) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test6() : Boolean {
|
||||||
|
var mnr = Array<MyNumber>(2,{it -> MyNumber(42-it)})
|
||||||
|
mnr[1] = mnr[0]++
|
||||||
|
if (mnr[0].i != 43) return false
|
||||||
|
if (mnr[1].i != 42) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
fun test7() : Boolean {
|
||||||
|
var mnr = ArrayList<MyNumber>()
|
||||||
|
mnr.add(MyNumber(42))
|
||||||
|
mnr[0]++
|
||||||
|
if (mnr[0].i != 43) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test8() : Boolean {
|
||||||
|
var mnr = ArrayList<MyNumber>()
|
||||||
|
mnr.add(MyNumber(42))
|
||||||
|
mnr.add(MyNumber(41))
|
||||||
|
mnr[1] = mnr[0]++
|
||||||
|
if (mnr[0].i != 43) return false
|
||||||
|
if (mnr[1].i != 42) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun box() : String {
|
||||||
|
var m = MyNumber(42)
|
||||||
|
|
||||||
|
if (!test1()) return "fail test 1"
|
||||||
|
if (!test2()) return "fail test 2"
|
||||||
|
if (!test3()) return "fail test 3"
|
||||||
|
if (!test4()) return "fail test 4"
|
||||||
|
if (!test5()) return "fail test 5"
|
||||||
|
if (!test6()) return "fail test 6"
|
||||||
|
/*
|
||||||
|
if (!test7()) return "fail test 7"
|
||||||
|
if (!test8()) return "fail test 8"
|
||||||
|
|
||||||
|
|
||||||
|
++m
|
||||||
|
if (m.i != 44) return "fail 0"
|
||||||
|
|
||||||
|
var m1 = ++m
|
||||||
|
if (m1.i != 46) return "fail 3"
|
||||||
|
if (m.i != 46) return "fail 4"
|
||||||
|
*/
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -261,4 +261,8 @@ public class ClassGenTest extends CodegenTestCase {
|
|||||||
public void testkt1157() throws Exception {
|
public void testkt1157() throws Exception {
|
||||||
blackBoxFile("regressions/kt1157.kt");
|
blackBoxFile("regressions/kt1157.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testkt471() throws Exception {
|
||||||
|
blackBoxFile("regressions/kt471.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user