diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index ad4451cfb21..1fc74d3e358 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -279,7 +279,7 @@ public class ExpressionCodegen extends JetVisitor implem public StackValue visitSuperExpression(JetSuperExpression expression, StackValue data) { final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference()); if (descriptor instanceof ClassDescriptor) { - return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor); + return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor, true); } else { JetType type = context.getThisDescriptor().getDefaultType(); @@ -1104,7 +1104,7 @@ public class ExpressionCodegen extends JetVisitor implem if (!ignoreThisAndReceiver) { final ClassDescriptor captureThis = closure.getCaptureThis(); if (captureThis != null) { - generateThisOrOuter(captureThis).put(OBJECT_TYPE, v); + generateThisOrOuter(captureThis, false).put(OBJECT_TYPE, v); } final ClassifierDescriptor captureReceiver = closure.getCaptureReceiver(); @@ -1370,14 +1370,14 @@ public class ExpressionCodegen extends JetVisitor implem if (!isStatic) { if (receiver == StackValue.none()) { if (resolvedCall == null) { - receiver = generateThisOrOuter((ClassDescriptor) propertyDescriptor.getContainingDeclaration()); + receiver = generateThisOrOuter((ClassDescriptor) propertyDescriptor.getContainingDeclaration(), false); } else { if (resolvedCall.getThisObject() instanceof ExtensionReceiver) { receiver = generateReceiver(((ExtensionReceiver) resolvedCall.getThisObject()).getDeclarationDescriptor()); } else { - receiver = generateThisOrOuter((ClassDescriptor) propertyDescriptor.getContainingDeclaration()); + receiver = generateThisOrOuter((ClassDescriptor) propertyDescriptor.getContainingDeclaration(), false); } } } @@ -1448,7 +1448,7 @@ public class ExpressionCodegen extends JetVisitor implem JvmClassName scriptClassName = classNameForScriptDescriptor(bindingContext, scriptDescriptor); ValueParameterDescriptor valueParameterDescriptor = (ValueParameterDescriptor) descriptor; final ClassDescriptor scriptClass = bindingContext.get(CLASS_FOR_FUNCTION, scriptDescriptor); - final StackValue script = StackValue.thisOrOuter(this, scriptClass); + final StackValue script = StackValue.thisOrOuter(this, scriptClass, false); script.put(script.type, v); Type fieldType = typeMapper.mapType(valueParameterDescriptor.getType(), JetTypeMapperMode.VALUE); return StackValue.field(fieldType, scriptClassName, valueParameterDescriptor.getName().getIdentifier(), false); @@ -1687,7 +1687,7 @@ public class ExpressionCodegen extends JetVisitor implem final JetExpression receiverExpression = ((ExpressionReceiver) explicitReceiver).getExpression(); if (receiverExpression instanceof JetSuperExpression) { superCall = true; - receiver = StackValue.thisOrOuter(this, context.getThisDescriptor()); + receiver = StackValue.thisOrOuter(this, context.getThisDescriptor(), true); JetSuperExpression superExpression = (JetSuperExpression) receiverExpression; PsiElement enclosingElement = bindingContext.get(BindingContext.LABEL_TARGET, superExpression.getTargetLabel()); ClassDescriptor enclosed = (ClassDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, enclosingElement); @@ -1706,7 +1706,7 @@ public class ExpressionCodegen extends JetVisitor implem fd = unwrapFakeOverride(fd); fd = (FunctionDescriptor) c.getAccessor(fd); superCall = false; - receiver = StackValue.thisOrOuter(this, enclosed); + receiver = StackValue.thisOrOuter(this, enclosed, true); } } } @@ -1877,7 +1877,7 @@ public class ExpressionCodegen extends JetVisitor implem StackValue.onStack(exprType).put(type, v); } else { - StackValue.thisOrOuter(this, classReceiverDeclarationDescriptor).put(type, v); + StackValue.thisOrOuter(this, classReceiverDeclarationDescriptor, false).put(type, v); } } else if (descriptor instanceof ScriptReceiver) { @@ -1963,7 +1963,7 @@ public class ExpressionCodegen extends JetVisitor implem throw new UnsupportedOperationException(); } - public StackValue generateThisOrOuter(@NotNull final ClassDescriptor calleeContainingClass) { + public StackValue generateThisOrOuter(@NotNull final ClassDescriptor calleeContainingClass, boolean isSuper) { PsiElement psiElement = classDescriptorToDeclaration(bindingContext, calleeContainingClass); boolean isObject = psiElement instanceof JetClassOrObject && isNonLiteralObject((JetClassOrObject) psiElement); @@ -1975,11 +1975,11 @@ public class ExpressionCodegen extends JetVisitor implem cur = cur.getParentContext(); } - assert cur != null; final ClassDescriptor thisDescriptor = cur.getThisDescriptor(); - if (DescriptorUtils.isSubclass(thisDescriptor, calleeContainingClass)) { - if (!isObject || (thisDescriptor == calleeContainingClass)) { + if (!isSuper && thisDescriptor.equals(calleeContainingClass) + || isSuper && DescriptorUtils.isSubclass(thisDescriptor, calleeContainingClass)) { + if (!isObject || (thisDescriptor.equals(calleeContainingClass))) { return castToRequiredTypeOfInterfaceIfNeeded(result, thisDescriptor, calleeContainingClass); } else { @@ -3105,7 +3105,7 @@ public class ExpressionCodegen extends JetVisitor implem public StackValue visitThisExpression(JetThisExpression expression, StackValue receiver) { final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference()); if (descriptor instanceof ClassDescriptor) { - return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor); + return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor, false); } else { if (descriptor instanceof CallableDescriptor) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index b02a2fa2f88..711d96a0cf0 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -959,7 +959,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { FrameMap frameMap = context.prepareFrame(state.getTypeMapper()); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getAsmMethod().getReturnType(), context, state); - codegen.generateThisOrOuter(descriptor); // ??? wouldn't it be addClosureToConstructorParameters good idea to put it? + codegen.generateThisOrOuter(descriptor, false); // ??? wouldn't it be addClosureToConstructorParameters good idea to put it? Type[] argTypes = function.getArgumentTypes(); List originalArgTypes = jvmSignature.getValueParameterTypes(); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java index 71cae271bba..cab3032d758 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java @@ -330,8 +330,8 @@ public abstract class StackValue { return new Composed(prefix, suffix); } - public static StackValue thisOrOuter(ExpressionCodegen codegen, ClassDescriptor descriptor) { - return new ThisOuter(codegen, descriptor); + public static StackValue thisOrOuter(ExpressionCodegen codegen, ClassDescriptor descriptor, boolean isSuper) { + return new ThisOuter(codegen, descriptor, isSuper); } public static StackValue postIncrement(int index, int increment) { @@ -1151,16 +1151,18 @@ public abstract class StackValue { private static class ThisOuter extends StackValue { private final ExpressionCodegen codegen; private final ClassDescriptor descriptor; + private final boolean isSuper; - public ThisOuter(ExpressionCodegen codegen, ClassDescriptor descriptor) { + public ThisOuter(ExpressionCodegen codegen, ClassDescriptor descriptor, boolean isSuper) { super(OBJECT_TYPE); this.codegen = codegen; this.descriptor = descriptor; + this.isSuper = isSuper; } @Override public void put(Type type, InstructionAdapter v) { - final StackValue stackValue = codegen.generateThisOrOuter(descriptor); + final StackValue stackValue = codegen.generateThisOrOuter(descriptor, isSuper); stackValue.put(stackValue.type, v); // no coercion here } } diff --git a/compiler/testData/codegen/objects/flist.kt b/compiler/testData/codegen/objects/flist.kt new file mode 100644 index 00000000000..b85c8f4884e --- /dev/null +++ b/compiler/testData/codegen/objects/flist.kt @@ -0,0 +1,53 @@ +public abstract class FList() { + public abstract val head: T + public abstract val tail: FList + public abstract val empty: Boolean + + class object { + val emptyFList = object: FList() { + public override val head: Any + get() = throw UnsupportedOperationException(); + + public override val tail: FList + get() = this + + public override val empty: Boolean + get() = true + } + } + + public fun plus(head: T): FList = object : FList() { + override public val head: T + get() = head + + override public val empty: Boolean + get() = false + + override public val tail: FList + get() = this@FList + } +} + +public fun emptyFList(): FList = FList.emptyFList as FList + +public fun FList.reverse(where: FList = emptyFList()) : FList = + if(empty) where else tail.reverse(where + head) + +public fun FList.iterator(): Iterator = object: Iterator { + private var cur: FList = this@iterator + + override public fun next(): T { + val res = cur.head + cur = cur.tail + return res + } + override public fun hasNext(): Boolean = !cur.empty +} + +fun box() : String { + var r = "" + for(s in (emptyFList() + "O" + "K").reverse()) { + r += s + } + return r +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/ObjectGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ObjectGenTest.java index aadef5152c9..4d1e2825f18 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ObjectGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ObjectGenTest.java @@ -91,4 +91,8 @@ public class ObjectGenTest extends CodegenTestCase { public void testThisInConstructor() { blackBoxFile("objects/thisInConstructor.kt"); } + + public void testFlist() { + blackBoxFile("objects/flist.kt"); + } }