when calling extension function, correctly put receiver on top of stack if it was generated before the extension function object (KT-1918)

This commit is contained in:
Dmitry Jemerov
2012-06-02 19:50:14 +02:00
parent 46bc7cf12f
commit ba9c3d73e7
3 changed files with 59 additions and 5 deletions
@@ -61,6 +61,18 @@ public abstract class StackValue {
public abstract void put(Type type, InstructionAdapter v);
/**
* This method is called to put the value on the top of the JVM stack if <code>depth</code> other values have been put on the
* JVM stack after this value was generated.
*
* @param type the type as which the value should be put
* @param v the visitor used to generate the instructions
* @param depth the number of new values put onto the stack
*/
public void moveToTopOfStack(Type type, InstructionAdapter v, int depth) {
put(type, v);
}
public void store(InstructionAdapter v) {
throw new UnsupportedOperationException("cannot store to value " + this);
}
@@ -341,6 +353,22 @@ public abstract class StackValue {
coerce(type, v);
}
}
@Override
public void moveToTopOfStack(Type type, InstructionAdapter v, int depth) {
if (depth == 0) {
put(type, v);
}
else if (depth == 1) {
if (type.getSize() != 1) {
throw new UnsupportedOperationException("don't know how to move type " + type + " to top of stack");
}
v.swap();
}
else {
throw new UnsupportedOperationException("unsupported move-to-top depth " + depth);
}
}
}
public static class Constant extends StackValue {
@@ -1132,20 +1160,21 @@ public abstract class StackValue {
else {
codegen.generateFromResolvedCall(thisObject, codegen.typeMapper.mapType(descriptor.getExpectedThisObject().getType(), MapTypeMode.VALUE));
}
genReceiver(v, receiverArgument, type, descriptor.getReceiverParameter());
genReceiver(v, receiverArgument, type, descriptor.getReceiverParameter(), 1);
}
else {
genReceiver(v, thisObject, type, null);
genReceiver(v, thisObject, type, null, 0);
}
}
else {
if (receiverArgument.exists()) {
genReceiver(v, receiverArgument, type, descriptor.getReceiverParameter());
genReceiver(v, receiverArgument, type, descriptor.getReceiverParameter(), 0);
}
}
}
private void genReceiver(InstructionAdapter v, ReceiverDescriptor receiverArgument, Type type, ReceiverDescriptor receiverParameter) {
private void genReceiver(InstructionAdapter v, ReceiverDescriptor receiverArgument, Type type,
@Nullable ReceiverDescriptor receiverParameter, int depth) {
if(receiver == StackValue.none()) {
if(receiverParameter != null) {
Type receiverType = codegen.typeMapper.mapType(receiverParameter.getType(), MapTypeMode.VALUE);
@@ -1157,7 +1186,7 @@ public abstract class StackValue {
}
}
else {
receiver.put(type, v);
receiver.moveToTopOfStack(type, v, depth);
}
}
}
@@ -0,0 +1,20 @@
class Bar {
}
trait Foo {
fun xyzzy(x: Any?): String
}
fun buildFoo(bar: Bar.() -> Unit): Foo {
return object : Foo {
override fun xyzzy(x: Any?): String {
(x as? Bar)?.bar()
return "OK"
}
}
}
fun box(): String {
val foo = buildFoo({})
return foo.xyzzy(Bar())
}
@@ -386,4 +386,9 @@ public class ClassGenTest extends CodegenTestCase {
createEnvironmentWithMockJdkAndIdeaAnnotations(CompilerSpecialMode.JDK_HEADERS);
blackBoxFile("classes/resolveOrder.jet");
}
public void testKt1918() throws Exception {
createEnvironmentWithMockJdkAndIdeaAnnotations(CompilerSpecialMode.JDK_HEADERS);
blackBoxFile("regressions/kt1918.kt");
}
}