From efceb12f3b93ab2128f583ef76714c60ea41d5b5 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Tue, 22 Nov 2011 12:35:42 +0200 Subject: [PATCH] rewrite of closure capturing for object literals --- .../jetbrains/jet/codegen/ClosureCodegen.java | 13 +- .../jetbrains/jet/codegen/CodegenContext.java | 32 +++++ .../jetbrains/jet/codegen/CodegenUtil.java | 3 + .../jet/codegen/ExpressionCodegen.java | 64 +++++----- .../jet/codegen/FunctionCodegen.java | 2 +- .../codegen/ImplementationBodyCodegen.java | 114 ++++++++---------- .../jetbrains/jet/codegen/JetTypeMapper.java | 20 +++ .../jet/codegen/ObjectOrClosureCodegen.java | 7 +- .../jet/codegen/TraitImplBodyCodegen.java | 2 + .../codegen/intrinsics/IntrinsicMethods.java | 16 ++- .../jet/codegen/intrinsics/IteratorNext.java | 42 +++++++ compiler/frontend/src/jet/Library.jet | 50 +++++--- .../testData/codegen/inputStreamIterator.jet | 26 ++++ .../jetbrains/jet/codegen/ArrayGenTest.java | 49 ++++++++ .../jetbrains/jet/codegen/ClassGenTest.java | 9 +- .../org/jetbrains/jet/codegen/StdlibTest.java | 10 ++ stdlib/ktSrc/StandardLibrary.kt | 36 ++++++ stdlib/src/jet/BooleanIterator.java | 8 ++ stdlib/src/jet/ByteIterator.java | 8 ++ stdlib/src/jet/CharIterator.java | 8 ++ stdlib/src/jet/DefaultJetObject.java | 7 ++ stdlib/src/jet/DoubleIterator.java | 8 ++ stdlib/src/jet/ExtensionFunction0.java | 2 +- stdlib/src/jet/FloatIterator.java | 8 ++ stdlib/src/jet/IntIterator.java | 8 ++ stdlib/src/jet/LongIterator.java | 8 ++ stdlib/src/jet/ShortIterator.java | 8 ++ 27 files changed, 435 insertions(+), 133 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IteratorNext.java create mode 100644 compiler/testData/codegen/inputStreamIterator.jet create mode 100644 compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 7cc17e458e2..c38fa4541cf 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -98,7 +98,8 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { captureThis = generateBody(funDescriptor, cv, fun.getFunctionLiteral()); ClassDescriptor thisDescriptor = context.getThisDescriptor(); final Type enclosingType = thisDescriptor == null ? null : Type.getObjectType(thisDescriptor.getName()); - if (enclosingType == null) captureThis = false; + if (enclosingType == null) + captureThis = false; final Method constructor = generateConstructor(funClass, fun); @@ -208,14 +209,14 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { private Method generateConstructor(String funClass, JetFunctionLiteralExpression fun) { int argCount = captureThis ? 1 : 0; + argCount += (captureReceiver != null ? 1 : 0); for (DeclarationDescriptor descriptor : closure.keySet()) { - if(descriptor instanceof VariableDescriptor) { + if(descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) { argCount++; } else if(descriptor instanceof FunctionDescriptor) { - captureReceiver = state.getTypeMapper().mapType(((FunctionDescriptor) descriptor).getReceiverParameter().getType()); - argCount++; + assert captureReceiver != null; } } @@ -231,8 +232,8 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { } for (DeclarationDescriptor descriptor : closure.keySet()) { - if(descriptor instanceof VariableDescriptor) { - final Type sharedVarType = exprContext.getSharedVarType(descriptor); + if(descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) { + final Type sharedVarType = exprContext.getTypeMapper().getSharedVarType(descriptor); final Type type = sharedVarType != null ? sharedVarType : state.getTypeMapper().mapType(((VariableDescriptor) descriptor).getOutType()); argTypes[i++] = type; } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java index 0b39bc09343..ce0eb62f800 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java @@ -21,6 +21,11 @@ public abstract class CodegenContext { protected ClassDescriptor getThisDescriptor() { return null; } + + @Override + public boolean isStatic() { + return true; + } }; protected static final StackValue local0 = StackValue.local(0, JetTypeMapper.TYPE_OBJECT); @@ -244,6 +249,8 @@ public abstract class CodegenContext { return getThisDescriptor() != null ? StackValue.local(1, asmType) : StackValue.local(0, asmType); } + public abstract boolean isStatic(); + public abstract static class ReceiverContext extends CodegenContext { final CallableDescriptor receiverDescriptor; @@ -276,6 +283,11 @@ public abstract class CodegenContext { return getParentContext().enclosingClassType(); } + @Override + public boolean isStatic() { + return getParentContext().isStatic(); + } + protected StackValue getOuterExpression(StackValue prefix) { return getParentContext().getOuterExpression(prefix); } @@ -310,6 +322,11 @@ public abstract class CodegenContext { protected ClassDescriptor getThisDescriptor() { return (ClassDescriptor) getContextDescriptor(); } + + @Override + public boolean isStatic() { + return false; + } } public static class AnonymousClassContext extends CodegenContext { @@ -326,6 +343,11 @@ public abstract class CodegenContext { protected ClassDescriptor getThisDescriptor() { return (ClassDescriptor) getContextDescriptor(); } + + @Override + public boolean isStatic() { + return false; + } } public static class ClosureContext extends ReceiverContext { @@ -350,6 +372,11 @@ public abstract class CodegenContext { public DeclarationDescriptor getContextDescriptor() { return classDescriptor; } + + @Override + public boolean isStatic() { + return false; + } } public static class NamespaceContext extends CodegenContext { @@ -361,5 +388,10 @@ public abstract class CodegenContext { protected ClassDescriptor getThisDescriptor() { return null; } + + @Override + public boolean isStatic() { + return true; + } } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java index 0aabf7ba086..fc16f243eab 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java @@ -89,6 +89,9 @@ public class CodegenUtil { } public static boolean hasTypeInfoField(JetType type) { + if(isInterface(type)) + return false; + List parameters = type.getConstructor().getParameters(); for (TypeParameterDescriptor parameter : parameters) { if(parameter.isReified()) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 0639e1a31c2..87c4bb9bd30 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -81,7 +81,7 @@ public class ExpressionCodegen extends JetVisitor { this.intrinsics = state.getIntrinsics(); } - StackValue castToRequiredTypeOfInterfaceIfNeeded(StackValue inner, DeclarationDescriptor provided, ClassDescriptor required) { + StackValue castToRequiredTypeOfInterfaceIfNeeded(StackValue inner, DeclarationDescriptor provided, @Nullable ClassDescriptor required) { if(required == null) return inner; @@ -640,13 +640,19 @@ public class ExpressionCodegen extends JetVisitor { v.load(0, JetTypeMapper.TYPE_OBJECT); } - for (DeclarationDescriptor descriptor : closureCodegen.closure.keySet()) { - Type sharedVarType = getSharedVarType(descriptor); - if(sharedVarType == null) - sharedVarType = state.getTypeMapper().mapType(((VariableDescriptor) descriptor).getOutType()); - consArgTypes.add(sharedVarType); - final EnclosedValueDescriptor valueDescriptor = closureCodegen.closure.get(descriptor); - valueDescriptor.getOuterValue().put(sharedVarType, v); + if(closureCodegen.captureReceiver != null) { + v.load(context.isStatic() ? 0 : 1, closureCodegen.captureReceiver); + consArgTypes.add(closureCodegen.captureReceiver); + } + + for (Map.Entry entry : closureCodegen.closure.entrySet()) { + if(entry.getKey() instanceof VariableDescriptor && !(entry.getKey() instanceof PropertyDescriptor)) { + Type sharedVarType = typeMapper.getSharedVarType(entry.getKey()); + if(sharedVarType == null) + sharedVarType = state.getTypeMapper().mapType(((VariableDescriptor) entry.getKey()).getOutType()); + consArgTypes.add(sharedVarType); + entry.getValue().getOuterValue().put(sharedVarType, v); + } } Method cons = new Method("", Type.VOID_TYPE, consArgTypes.toArray(new Type[consArgTypes.size()])); @@ -654,20 +660,6 @@ public class ExpressionCodegen extends JetVisitor { return StackValue.onStack(Type.getObjectType(closure.getClassname())); } - Type getSharedVarType(DeclarationDescriptor variableDescriptor) { - if(!(variableDescriptor instanceof VariableDescriptor)) - return null; - - Boolean aBoolean = bindingContext.get(BindingContext.MUST_BE_WRAPPED_IN_A_REF, (VariableDescriptor) variableDescriptor); - if (aBoolean != null && aBoolean) { - JetType outType = ((VariableDescriptor) variableDescriptor).getOutType(); - return StackValue.sharedTypeForType(typeMapper.mapType(outType)); - } - else { - return null; - } - } - private StackValue generateBlock(List statements) { Label blockStart = new Label(); v.mark(blockStart); @@ -677,7 +669,7 @@ public class ExpressionCodegen extends JetVisitor { final VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, statement); assert variableDescriptor != null; - final Type sharedVarType = getSharedVarType(variableDescriptor); + final Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor); final Type type = sharedVarType != null ? sharedVarType : typeMapper.mapType(variableDescriptor.getOutType()); myFrameMap.enter(variableDescriptor, type.getSize()); } @@ -705,7 +697,7 @@ public class ExpressionCodegen extends JetVisitor { int index = myFrameMap.leave(variableDescriptor); - final Type sharedVarType = getSharedVarType(variableDescriptor); + final Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor); final Type type = sharedVarType != null ? sharedVarType : typeMapper.mapType(variableDescriptor.getOutType()); if(sharedVarType != null) { v.aconst(null); @@ -819,7 +811,7 @@ public class ExpressionCodegen extends JetVisitor { else { int index = lookupLocal(descriptor); if (index >= 0) { - Type sharedVarType = getSharedVarType(descriptor); + Type sharedVarType = typeMapper.getSharedVarType(descriptor); final JetType outType = ((VariableDescriptor) descriptor).getOutType(); if(sharedVarType != null) { return StackValue.shared(index, typeMapper.mapType(outType)); @@ -914,7 +906,7 @@ public class ExpressionCodegen extends JetVisitor { receiver = generateThisOrOuter((ClassDescriptor) propertyDescriptor.getContainingDeclaration()); else { if(resolvedCall.getThisObject() instanceof ExtensionReceiver) - receiver = generateReceiver(((ExtensionReceiver)resolvedCall.getThisObject()).getDeclarationDescriptor(), null); + receiver = generateReceiver(((ExtensionReceiver)resolvedCall.getThisObject()).getDeclarationDescriptor()); else receiver = generateThisOrOuter((ClassDescriptor) propertyDescriptor.getContainingDeclaration()); } @@ -992,6 +984,12 @@ public class ExpressionCodegen extends JetVisitor { functionDescriptor = functionDescriptor.getOriginal(); String owner; + IntrinsicMethod intrinsic = intrinsics.getIntrinsic(functionDescriptor); + if(intrinsic != null) { + intrinsic.generate(this, v, type, null, null, StackValue.onStack(JetTypeMapper.TYPE_OBJECT)); + return; + } + boolean isInterface; boolean isInsideClass = containingDeclaration == context.getThisDescriptor(); if (isInsideClass || isStatic) { @@ -1247,7 +1245,7 @@ public class ExpressionCodegen extends JetVisitor { } else if(descriptor instanceof ExtensionReceiver) { ExtensionReceiver extensionReceiver = (ExtensionReceiver) descriptor; - generateReceiver(extensionReceiver.getDeclarationDescriptor(), null).put(typeMapper.mapType(descriptor.getType()), v); + generateReceiver(extensionReceiver.getDeclarationDescriptor()).put(typeMapper.mapType(descriptor.getType()), v); } else if(descriptor instanceof ExpressionReceiver) { ExpressionReceiver expressionReceiver = (ExpressionReceiver) descriptor; @@ -1266,16 +1264,16 @@ public class ExpressionCodegen extends JetVisitor { return null; } - private StackValue generateReceiver(DeclarationDescriptor provided, ClassDescriptor required) { + private StackValue generateReceiver(DeclarationDescriptor provided) { assert context instanceof CodegenContext.ReceiverContext; CodegenContext.ReceiverContext cur = (CodegenContext.ReceiverContext) context; if (cur.getReceiverDescriptor() == provided) { StackValue result = cur.getReceiverExpression(typeMapper); - return castToRequiredTypeOfInterfaceIfNeeded(result, provided, required); + return castToRequiredTypeOfInterfaceIfNeeded(result, provided, null); } StackValue result = context.lookupInContext(provided, v, StackValue.local(0, JetTypeMapper.TYPE_OBJECT)); - return castToRequiredTypeOfInterfaceIfNeeded(result, provided, required); + return castToRequiredTypeOfInterfaceIfNeeded(result, provided, null); } public StackValue generateThisOrOuter(ClassDescriptor calleeContainingClass) { @@ -1939,7 +1937,7 @@ public class ExpressionCodegen extends JetVisitor { assert index >= 0; - final Type sharedVarType = getSharedVarType(variableDescriptor); + final Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor); assert variableDescriptor != null; Type varType = typeMapper.mapType(variableDescriptor.getOutType()); if(sharedVarType != null) { @@ -2217,8 +2215,8 @@ public class ExpressionCodegen extends JetVisitor { return generateThisOrOuter((ClassDescriptor) descriptor); } else { - if(descriptor instanceof FunctionDescriptor) { - return generateReceiver(descriptor, null); + if(descriptor instanceof FunctionDescriptor || descriptor instanceof PropertyDescriptor) { + return generateReceiver(descriptor); } throw new UnsupportedOperationException(); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index cc5a593222f..ee11e6e98e0 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -110,7 +110,7 @@ public class FunctionCodegen { } else { for (ValueParameterDescriptor parameter : paramDescrs) { - Type sharedVarType = codegen.getSharedVarType(parameter); + Type sharedVarType = state.getTypeMapper().getSharedVarType(parameter); Type localVarType = state.getTypeMapper().mapType(parameter.getOutType()); if (sharedVarType != null) { int index = frameMap.getIndex(parameter); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 53f02d5bea2..854f32e53e6 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -1,6 +1,5 @@ package org.jetbrains.jet.codegen; -import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; @@ -39,43 +38,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { private Set getSuperInterfaces(JetClassOrObject aClass) { List delegationSpecifiers = aClass.getDelegationSpecifiers(); - String superClassName = null; Set superInterfaces = new LinkedHashSet(); for (JetDelegationSpecifier specifier : delegationSpecifiers) { JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference()); assert superType != null; ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); - PsiElement superPsi = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, superClassDescriptor); - - if (superPsi instanceof PsiClass) { - PsiClass psiClass = (PsiClass) superPsi; - String fqn = psiClass.getQualifiedName(); - assert fqn != null; - if (psiClass.isInterface()) { - superInterfaces.add(fqn.replace('.', '/')); - } - else { - if (superClassName == null) { - superClassName = fqn.replace('.', '/'); - - while (psiClass != null) { - for (PsiClass ifs : psiClass.getInterfaces()) { - String qualifiedName = ifs.getQualifiedName(); - assert qualifiedName != null; - superInterfaces.add(qualifiedName.replace('.', '/')); - } - psiClass = psiClass.getSuperClass(); - } - } - else { - throw new RuntimeException("Cannot determine single class to inherit from"); - } - } - } - else { - if(superPsi == null || ((JetClass)superPsi).isTrait()) - superInterfaces.add(typeMapper.mapType(superClassDescriptor.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName()); + if(CodegenUtil.isInterface(superClassDescriptor)) { + superInterfaces.add(typeMapper.getFQName(superClassDescriptor)); } } return superInterfaces; @@ -137,21 +107,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference()); assert superType != null; ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); - final PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, superClassDescriptor); - if (declaration != null) { - if (declaration instanceof PsiClass) { - if (!((PsiClass) declaration).isInterface()) { - superClass = typeMapper.mapType(superClassDescriptor.getDefaultType(), kind).getInternalName(); - superCall = specifier; - return; - } - } - else if(declaration instanceof JetClass) { - if(!((JetClass) declaration).isTrait()) { - superClass = typeMapper.mapType(superClassDescriptor.getDefaultType(), kind).getInternalName(); - superCall = specifier; - } - } + if(!CodegenUtil.isInterface(superClassDescriptor)) { + superClass = typeMapper.mapType(superClassDescriptor.getDefaultType(), kind).getInternalName(); + superCall = specifier; } } } @@ -332,16 +290,33 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { method = callableMethod.getSignature(); } - int firstClosureIndex = -1; - if(context.closure != null) { + ObjectOrClosureCodegen closure = context.closure; + if(closure != null) { final List consArgTypes = new LinkedList(Arrays.asList(method.getArgumentTypes())); - firstClosureIndex = consArgTypes.size()+1; + int insert = 0; + if(closure.captureThis) { + if(!CodegenUtil.hasThis0(descriptor)) + consArgTypes.add(insert, Type.getObjectType(context.getThisDescriptor().getName())); + insert++; + } + else { + if(CodegenUtil.hasThis0(descriptor)) + insert++; + } - Map closure = context.closure.closure; - for (DeclarationDescriptor descriptor : closure.keySet()) { - final Type sharedVarType = context.closure.exprContext.getSharedVarType(descriptor); - consArgTypes.add(sharedVarType != null ? sharedVarType : typeMapper.mapType(((VariableDescriptor) descriptor).getOutType())); + if(closure.captureReceiver != null) + consArgTypes.add(insert++, closure.captureReceiver); + + for (DeclarationDescriptor descriptor : closure.closure.keySet()) { + if(descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) { + final Type sharedVarType = typeMapper.getSharedVarType(descriptor); + final Type type = sharedVarType != null ? sharedVarType : state.getTypeMapper().mapType(((VariableDescriptor) descriptor).getOutType()); + consArgTypes.add(insert++, type); + } + else if(descriptor instanceof FunctionDescriptor) { + assert closure.captureReceiver != null; + } } method = new Method("", Type.VOID_TYPE, consArgTypes.toArray(new Type[consArgTypes.size()])); @@ -450,17 +425,28 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { generateTypeInfoInitializer(frameMap.getFirstTypeParameter(), frameMap.getTypeParameterCount(), iv); } - if(context.closure != null) { - Map closure = context.closure.closure; - int k = 0; - for (DeclarationDescriptor varDescr : closure.keySet()) { - Type sharedVarType = context.closure.exprContext.getSharedVarType(varDescr); - if(sharedVarType == null) { - sharedVarType = typeMapper.mapType(((VariableDescriptor) varDescr).getOutType()); - } + if(closure != null) { + int k = outerDescriptor != null && outerDescriptor.getKind() != ClassKind.OBJECT ? 2 : 1; + if(closure.captureReceiver != null) { iv.load(0, JetTypeMapper.TYPE_OBJECT); - iv.load(firstClosureIndex + k, StackValue.refType(sharedVarType)); - iv.putfield(typeMapper.mapType(descriptor.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(), "$" + (k+1), sharedVarType.getDescriptor()); + iv.load(1, closure.captureReceiver); + iv.putfield(typeMapper.mapType(descriptor.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(), "receiver$0", closure.captureReceiver.getDescriptor()); + k += closure.captureReceiver.getSize(); + } + + int l = 0; + for (DeclarationDescriptor varDescr : closure.closure.keySet()) { + if(varDescr instanceof VariableDescriptor && !(varDescr instanceof PropertyDescriptor)) { + Type sharedVarType = typeMapper.getSharedVarType(varDescr); + if(sharedVarType == null) { + sharedVarType = typeMapper.mapType(((VariableDescriptor) varDescr).getOutType()); + } + iv.load(0, JetTypeMapper.TYPE_OBJECT); + iv.load(k, StackValue.refType(sharedVarType)); + k += StackValue.refType(sharedVarType).getSize(); + iv.putfield(typeMapper.mapType(descriptor.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(), "$" + (l+1), sharedVarType.getDescriptor()); + l++; + } } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index c692f16e199..16a4a1b2430 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -664,4 +664,24 @@ public class JetTypeMapper { JetType type = arrayType.getArguments().get(0).getType(); return isGenericsArray(type) ? type : null; } + + public Type getSharedVarType(DeclarationDescriptor descriptor) { + if(descriptor instanceof PropertyDescriptor) { + return StackValue.sharedTypeForType(mapType(((PropertyDescriptor) descriptor).getReceiverParameter().getType())); + } + else if (descriptor instanceof FunctionDescriptor) { + return StackValue.sharedTypeForType(mapType(((FunctionDescriptor) descriptor).getReceiverParameter().getType())); + } + else if (descriptor instanceof VariableDescriptor) { + Boolean aBoolean = bindingContext.get(BindingContext.MUST_BE_WRAPPED_IN_A_REF, (VariableDescriptor) descriptor); + if (aBoolean != null && aBoolean) { + JetType outType = ((VariableDescriptor) descriptor).getOutType(); + return StackValue.sharedTypeForType(mapType(outType)); + } + else { + return null; + } + } + return null; + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java index d9c6f261a24..c1982e6167d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java @@ -34,13 +34,13 @@ public class ObjectOrClosureCodegen { return result != null ? innerValue : StackValue.composed(result, innerValue); } - if (d instanceof VariableDescriptor) { + if (d instanceof VariableDescriptor && !(d instanceof PropertyDescriptor)) { VariableDescriptor vd = (VariableDescriptor) d; final int idx = exprContext.lookupLocal(vd); if (idx < 0) return null; - final Type sharedVarType = exprContext.getSharedVarType(vd); + final Type sharedVarType = state.getTypeMapper().getSharedVarType(vd); Type localType = state.getTypeMapper().mapType(vd.getOutType()); final Type type = sharedVarType != null ? sharedVarType : localType; @@ -79,6 +79,9 @@ public class ObjectOrClosureCodegen { answer = new EnclosedValueDescriptor(d, innerValue, outerValue); closure.put(d, answer); + assert captureReceiver == null; + captureReceiver = type; + return innerValue; } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java index 1653fa1984f..7ef9ef7be3f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java @@ -19,6 +19,8 @@ public class TraitImplBodyCodegen extends ClassBodyCodegen { //todo not needed when frontend will be able to calculate properly static JetType getSuperClass(ClassDescriptor myClassDescr, BindingContext bindingContext) { JetClassOrObject myClass = (JetClassOrObject) bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, myClassDescr); + if(myClass == null) + return JetStandardClasses.getAnyType(); List delegationSpecifiers = myClass.getDelegationSpecifiers(); for (JetDelegationSpecifier specifier : delegationSpecifiers) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java index 5ea6dc9faed..66551a76349 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java @@ -35,6 +35,7 @@ public class IntrinsicMethods { public static final IntrinsicMethod ARRAY_SIZE = new ArraySize(); public static final IntrinsicMethod ARRAY_INDICES = new ArrayIndices(); public static final Equals EQUALS = new Equals(); + public static final IteratorNext ITERATOR_NEXT = new IteratorNext(); private final Project myProject; private final JetStandardLibrary myStdLib; @@ -83,6 +84,15 @@ public class IntrinsicMethods { declareOverload(myStdLib.getLibraryScope().getFunctions("identityEquals"), 1, EQUALS); declareOverload(myStdLib.getLibraryScope().getFunctions("plus"), 1, new StringPlus()); + declareIntrinsicFunction("ByteIterator", "next", 0, ITERATOR_NEXT); + declareIntrinsicFunction("ShortIterator", "next", 0, ITERATOR_NEXT); + declareIntrinsicFunction("IntIterator", "next", 0, ITERATOR_NEXT); + declareIntrinsicFunction("LongIterator", "next", 0, ITERATOR_NEXT); + declareIntrinsicFunction("CharIterator", "next", 0, ITERATOR_NEXT); + declareIntrinsicFunction("BooleanIterator", "next", 0, ITERATOR_NEXT); + declareIntrinsicFunction("FloatIterator", "next", 0, ITERATOR_NEXT); + declareIntrinsicFunction("DoubleIterator", "next", 0, ITERATOR_NEXT); + // declareIntrinsicFunction("Any", "equals", 1, new Equals()); // declareIntrinsicStringMethods(); @@ -168,7 +178,11 @@ public class IntrinsicMethods { private void declareIntrinsicFunction(String className, String functionName, int arity, IntrinsicMethod implementation) { JetScope memberScope = getClassMemberScope(className); final Set group = memberScope.getFunctions(functionName); - declareOverload(group, arity, implementation); + for (FunctionDescriptor descriptor : group) { + if (className.equals(descriptor.getContainingDeclaration().getName()) && descriptor.getValueParameters().size() == arity) { + myMethods.put(descriptor.getOriginal(), implementation); + } + } } private void declareOverload(Set group, int arity, IntrinsicMethod implementation) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IteratorNext.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IteratorNext.java new file mode 100644 index 00000000000..d4a1217712e --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IteratorNext.java @@ -0,0 +1,42 @@ +package org.jetbrains.jet.codegen.intrinsics; + +import com.intellij.psi.PsiElement; +import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.JetTypeMapper; +import org.jetbrains.jet.codegen.StackValue; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.InstructionAdapter; + +import java.util.List; + +/** + * @author alex.tkachman + */ +public class IteratorNext implements IntrinsicMethod { + @Override + public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { + String name; + if(expectedType == Type.CHAR_TYPE) + name = "Char"; + else if(expectedType == Type.BOOLEAN_TYPE) + name = "Boolean"; + else if(expectedType == Type.BYTE_TYPE) + name = "Byte"; + else if(expectedType == Type.SHORT_TYPE) + name = "Short"; + else if(expectedType == Type.INT_TYPE) + name = "Int"; + else if(expectedType == Type.LONG_TYPE) + name = "Long"; + else if(expectedType == Type.FLOAT_TYPE) + name = "Float"; + else if(expectedType == Type.DOUBLE_TYPE) + name = "Double"; + else + throw new UnsupportedOperationException(); + receiver.put(JetTypeMapper.TYPE_OBJECT, v); + v.invokevirtual("jet/" + name + "Iterator", "next" + name, "()" + expectedType.getDescriptor()); + return StackValue.onStack(expectedType); + } +} diff --git a/compiler/frontend/src/jet/Library.jet b/compiler/frontend/src/jet/Library.jet index bf7e4c47147..24a7f4e962f 100644 --- a/compiler/frontend/src/jet/Library.jet +++ b/compiler/frontend/src/jet/Library.jet @@ -34,7 +34,7 @@ namespace io { fun readLine() : String? } -fun Any?.identityEquals(other : Any?) // = this === other +fun Any?.identityEquals(other : Any?) : Boolean // = this === other // Can't write a body due to a bootstrapping problem (see JET-74) fun Any?.equals(other : Any?) : Boolean// = this === other @@ -53,36 +53,52 @@ trait Iterator { val hasNext : Boolean } -abstract open class ByteIterator : Iterator { - fun nextByte() : Byte +abstract open class ByteIterator() : Iterator { + abstract open fun nextByte() : Byte + + override fun next() : Byte } -abstract open class ShortIterator : Iterator { - fun nextShort() : Short +abstract open class ShortIterator() : Iterator { + abstract open fun nextShort() : Short + + override fun next() : Short } -abstract open class CharIterator : Iterator { - fun nextChar() : Char +abstract open class CharIterator() : Iterator { + abstract open fun nextChar() : Char + + override fun next() : Char } -abstract open class IntIterator : Iterator { - fun nextInt() : Int +abstract open class IntIterator() : Iterator { + abstract open fun nextInt() : Int + + override fun next() : Int } -abstract open class LongIterator : Iterator { - fun nextLong() : Long +abstract open class LongIterator() : Iterator { + abstract open fun nextLong() : Long + + override fun next() : Long } -abstract open class FloatIterator : Iterator { - fun nextFloat() : Float +abstract open class FloatIterator() : Iterator { + abstract open fun nextFloat() : Float + + override fun next() : Float } -abstract open class DoubleIterator : Iterator { - fun nextDouble() : Double +abstract open class DoubleIterator() : Iterator { + abstract open fun nextDouble() : Double + + override fun next() : Double } -abstract open class BooleanIterator : Iterator { - fun nextBoolean() : Boolean +abstract open class BooleanIterator() : Iterator { + abstract open fun nextBoolean() : Boolean + + override fun next() : Boolean } trait Iterable { diff --git a/compiler/testData/codegen/inputStreamIterator.jet b/compiler/testData/codegen/inputStreamIterator.jet new file mode 100644 index 00000000000..2c1d4e89857 --- /dev/null +++ b/compiler/testData/codegen/inputStreamIterator.jet @@ -0,0 +1,26 @@ +import java.io.* + +val ByteArray.inputStream : ByteArrayInputStream + get() = ByteArrayInputStream(this) + +fun InputStream.iterator() : ByteIterator = + object: ByteIterator() { + override val hasNext : Boolean + get() = available() > 0 + + override fun nextByte() = read().byt + } + +fun box() : String { + val x = ByteArray (10) + + for(index in 0..9) { + x [index] = index.byt + } + + for(b in x.inputStream) { + System.out?.println(b) + } + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java index 3e4ffc3c033..c611dad097d 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java @@ -139,6 +139,55 @@ public class ArrayGenTest extends CodegenTestCase { foo.invoke(null); } + public void testByteIterator () throws Exception { + loadText("fun box() { val x = ByteArray(5).iterator(); while(x.hasNext) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } + + public void testShortIterator () throws Exception { + loadText("fun box() { val x = ShortArray(5).iterator(); while(x.hasNext) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } + + public void testIntIterator () throws Exception { + loadText("fun box() { val x = IntArray(5).iterator(); while(x.hasNext) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } + + public void testLongIterator2 () throws Exception { + loadText("fun box() { val x = LongArray(5).iterator(); while(x.hasNext) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } + + public void testFloatIterator () throws Exception { + loadText("fun box() { val x = FloatArray(5).iterator(); while(x.hasNext) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } + + public void testDoubleIterator () throws Exception { + loadText("fun box() { val x = ShortArray(5).iterator(); while(x.hasNext) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } + + public void testBooleanIterator () throws Exception { + loadText("fun box() { val x = BooleanArray(5).iterator(); while(x.hasNext) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } + public void testArrayIndices () throws Exception { loadText("fun box() { val x = Array(5, {it}).indices.iterator(); while(x.hasNext) { java.lang.System.out?.println(x.next()) } }"); System.out.println(generateToText()); diff --git a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java index a93627fc235..6b44f7b8d94 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -24,7 +24,7 @@ public class ClassGenTest extends CodegenTestCase { loadFile("classes/inheritingFromArrayList.jet"); final Class aClass = loadClass("Foo", generateClassesInFile()); - checkInterface(aClass, List.class); + assertInstanceOf(aClass.newInstance(), List.class); } public void testInheritanceAndDelegation_DelegatingDefaultConstructorProperties() throws Exception { @@ -47,13 +47,6 @@ public class ClassGenTest extends CodegenTestCase { blackBoxFile("classes/rightHandOverride.jet"); } - private static void checkInterface(Class aClass, Class ifs) { - for (Class anInterface : aClass.getInterfaces()) { - if (anInterface == ifs) return; - } - fail(aClass.getName() + " must have " + ifs.getName() + " in its interfaces"); - } - public void testNewInstanceExplicitConstructor() throws Exception { loadFile("classes/newInstanceDefaultConstructor.jet"); System.out.println(generateToText()); diff --git a/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java b/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java new file mode 100644 index 00000000000..0629cc70b9b --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java @@ -0,0 +1,10 @@ +package org.jetbrains.jet.codegen; + +/** + * @author alex.tkachman + */ +public class StdlibTest extends CodegenTestCase { + public void testInputStreamIterator () { + blackBoxFile("inputStreamIterator.jet"); + } +} diff --git a/stdlib/ktSrc/StandardLibrary.kt b/stdlib/ktSrc/StandardLibrary.kt index 9d944873b58..e4392e0c771 100644 --- a/stdlib/ktSrc/StandardLibrary.kt +++ b/stdlib/ktSrc/StandardLibrary.kt @@ -26,6 +26,42 @@ namespace io { inline fun println(message : CharArray) { System.out?.println(message) } inline fun println() { System.out?.println() } + val ByteArray.inputStream : ByteArrayInputStream + get() = ByteArrayInputStream(this) + + inline fun ByteArray.inputStream(offset: Int, length: Int) : ByteArrayInputStream = ByteArrayInputStream(this, offset, length) + + val InputStream.buffered : BufferedInputStream + get() = if(this instanceof BufferedInputStream) this else BufferedInputStream(this) + + inline fun InputStream.buffered(bufferSize: Int) = BufferedInputStream(this, bufferSize) + + val InputStream.reader : InputStreamReader + get() = InputStreamReader(this) + + val InputStream.bufferedReader : BufferedReader + get() = buffered.reader + + inline fun val InputStream.reader(charset: Charset) : InputStreamReader = InputStreamReader(this, charset) + + inline fun val InputStream.reader(charsetName: String) = InputStreamReader(this, charsetNme) + + inline fun val InputStream.reader(charset: Charset) = InputStreamReader(this, charset) + + inline fun val InputStream.reader(charsetDecoder: CharsetDecoder) = InputStreamReader(this, charsetDecoder) + + fun InputStream.iterator() : ByteIterator = object: ByteIterator() { + override val hasNext : Boolean + get() = available() > 0 + + override fun nextByte() = read().byt + } + + val Reader.buffered : BufferedReader + get() = if(this instanceof BufferedReader) this else BufferedReader(this) + + inline fun Reader.buffered(bufferSize: Int) = BufferedReader(this, bufferSize) + private val stdin : BufferedReader = BufferedReader(InputStreamReader(object : InputStream() { override fun read() : Int { return System.`in`?.read() ?: -1 diff --git a/stdlib/src/jet/BooleanIterator.java b/stdlib/src/jet/BooleanIterator.java index f1d04ab3eb9..a242e61274d 100644 --- a/stdlib/src/jet/BooleanIterator.java +++ b/stdlib/src/jet/BooleanIterator.java @@ -1,9 +1,17 @@ package jet; +import jet.typeinfo.TypeInfo; + /** * @author alex.tkachman */ public abstract class BooleanIterator implements Iterator { + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(BooleanIterator.class, false); + + public TypeInfo getTypeInfo () { + return typeInfo; + } + public final Boolean next() { return nextBoolean(); } diff --git a/stdlib/src/jet/ByteIterator.java b/stdlib/src/jet/ByteIterator.java index b1648e77ad2..a21be0e0e42 100644 --- a/stdlib/src/jet/ByteIterator.java +++ b/stdlib/src/jet/ByteIterator.java @@ -1,9 +1,17 @@ package jet; +import jet.typeinfo.TypeInfo; + /** * @author alex.tkachman */ public abstract class ByteIterator implements Iterator { + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(ByteIterator.class, false); + + public TypeInfo getTypeInfo () { + return typeInfo; + } + public final Byte next() { return nextByte(); } diff --git a/stdlib/src/jet/CharIterator.java b/stdlib/src/jet/CharIterator.java index d905636d6aa..27034e010a4 100644 --- a/stdlib/src/jet/CharIterator.java +++ b/stdlib/src/jet/CharIterator.java @@ -1,9 +1,17 @@ package jet; +import jet.typeinfo.TypeInfo; + /** * @author alex.tkachman */ public abstract class CharIterator implements Iterator { + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(CharIterator.class, false); + + public TypeInfo getTypeInfo () { + return typeInfo; + } + public final Character next() { return nextChar(); } diff --git a/stdlib/src/jet/DefaultJetObject.java b/stdlib/src/jet/DefaultJetObject.java index e5ce4f43185..4070c14eb5d 100644 --- a/stdlib/src/jet/DefaultJetObject.java +++ b/stdlib/src/jet/DefaultJetObject.java @@ -8,10 +8,17 @@ import jet.typeinfo.TypeInfo; public class DefaultJetObject implements JetObject { private TypeInfo typeInfo; + protected DefaultJetObject() { + } + protected DefaultJetObject(TypeInfo typeInfo) { this.typeInfo = typeInfo; } + protected final void $setTypeInfo(TypeInfo typeInfo) { + this.typeInfo = typeInfo; + } + @Override public final TypeInfo getTypeInfo() { return typeInfo; diff --git a/stdlib/src/jet/DoubleIterator.java b/stdlib/src/jet/DoubleIterator.java index 59f9b2f086e..5f01ae5eb5a 100644 --- a/stdlib/src/jet/DoubleIterator.java +++ b/stdlib/src/jet/DoubleIterator.java @@ -1,9 +1,17 @@ package jet; +import jet.typeinfo.TypeInfo; + /** * @author alex.tkachman */ public abstract class DoubleIterator implements Iterator { + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(DoubleIterator.class, false); + + public TypeInfo getTypeInfo () { + return typeInfo; + } + public final Double next() { return nextDouble(); } diff --git a/stdlib/src/jet/ExtensionFunction0.java b/stdlib/src/jet/ExtensionFunction0.java index 9d2e12fcc47..170f5c4bd69 100644 --- a/stdlib/src/jet/ExtensionFunction0.java +++ b/stdlib/src/jet/ExtensionFunction0.java @@ -5,7 +5,7 @@ package jet; import jet.typeinfo.TypeInfo; -public abstract class ExtensionFunction0 extends DefaultJetObject{ +public abstract class ExtensionFunction0 extends DefaultJetObject { protected ExtensionFunction0(TypeInfo typeInfo) { super(typeInfo); } diff --git a/stdlib/src/jet/FloatIterator.java b/stdlib/src/jet/FloatIterator.java index 9f5b08b2706..789fd5ae1a0 100644 --- a/stdlib/src/jet/FloatIterator.java +++ b/stdlib/src/jet/FloatIterator.java @@ -1,9 +1,17 @@ package jet; +import jet.typeinfo.TypeInfo; + /** * @author alex.tkachman */ public abstract class FloatIterator implements Iterator { + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(FloatIterator.class, false); + + public TypeInfo getTypeInfo () { + return typeInfo; + } + public final Float next() { return nextFloat(); } diff --git a/stdlib/src/jet/IntIterator.java b/stdlib/src/jet/IntIterator.java index 98807ff73f9..1e1dda6fbd7 100644 --- a/stdlib/src/jet/IntIterator.java +++ b/stdlib/src/jet/IntIterator.java @@ -1,9 +1,17 @@ package jet; +import jet.typeinfo.TypeInfo; + /** * @author alex.tkachman */ public abstract class IntIterator implements Iterator { + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(IntIterator.class, false); + + public TypeInfo getTypeInfo () { + return typeInfo; + } + public final Integer next() { return nextInt(); } diff --git a/stdlib/src/jet/LongIterator.java b/stdlib/src/jet/LongIterator.java index 307df356865..2827adabf9a 100644 --- a/stdlib/src/jet/LongIterator.java +++ b/stdlib/src/jet/LongIterator.java @@ -1,9 +1,17 @@ package jet; +import jet.typeinfo.TypeInfo; + /** * @author alex.tkachman */ public abstract class LongIterator implements Iterator { + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(LongIterator.class, false); + + public TypeInfo getTypeInfo () { + return typeInfo; + } + public final Long next() { return nextLong(); } diff --git a/stdlib/src/jet/ShortIterator.java b/stdlib/src/jet/ShortIterator.java index 32421f705b2..8f383faee63 100644 --- a/stdlib/src/jet/ShortIterator.java +++ b/stdlib/src/jet/ShortIterator.java @@ -1,9 +1,17 @@ package jet; +import jet.typeinfo.TypeInfo; + /** * @author alex.tkachman */ public abstract class ShortIterator implements Iterator { + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(ShortIterator.class, false); + + public TypeInfo getTypeInfo () { + return typeInfo; + } + public final Short next() { return nextShort(); }