diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 91c126fd77d..ea7afc3dd7b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -52,8 +52,10 @@ public class ExpressionCodegen extends JetVisitor { private final InstructionAdapter v; private final FrameMap myMap; private final JetTypeMapper typeMapper; + private final GenerationState state; private final Type returnType; + private final BindingContext bindingContext; private final Map typeParameterExpressions = new HashMap(); private final ClassContext context; @@ -74,6 +76,14 @@ public class ExpressionCodegen extends JetVisitor { this.intrinsics = state.getIntrinsics(); } + public GenerationState getState() { + return state; + } + + public BindingContext getBindingContext() { + return bindingContext; + } + public JetTypeMapper getTypeMapper() { return state.getTypeMapper(); } @@ -207,7 +217,7 @@ public class ExpressionCodegen extends JetVisitor { else { assert expressionType != null; final DeclarationDescriptor descriptor = expressionType.getConstructor().getDeclarationDescriptor(); - if (isClass(descriptor, "IntRange")) { // TODO IntRange subclasses + if (isClass(descriptor, "IntRange")) { // TODO IntRange subclasses (now IntRange is final) new ForInRangeLoopGenerator(expression, loopRangeType).invoke(); return StackValue.none(); } @@ -921,7 +931,7 @@ public class ExpressionCodegen extends JetVisitor { callableMethod = ClosureCodegen.asCallableMethod((FunctionDescriptor) fd); } else if (fd instanceof FunctionDescriptor) { - callableMethod = ClosureCodegen.asCallableMethod((FunctionDescriptor) fd); + callableMethod = typeMapper.mapToCallableMethod((FunctionDescriptor) fd, null); } else { throw new UnsupportedOperationException("can't resolve declaration to callable: " + fd); @@ -2076,7 +2086,7 @@ public class ExpressionCodegen extends JetVisitor { } } - void generateTypeInfo(JetType jetType) { + public void generateTypeInfo(JetType jetType) { String knownTypeInfo = typeMapper.isKnownTypeInfo(jetType); if(knownTypeInfo != null) { v.getstatic("jet/typeinfo/TypeInfo", knownTypeInfo, "Ljet/typeinfo/TypeInfo;"); @@ -2287,7 +2297,7 @@ public class ExpressionCodegen extends JetVisitor { JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, rangeExpression); assert jetType != null; final DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); - if (isClass(descriptor, "IntRange")) { // TODO IntRange subclasses + if (isClass(descriptor, "IntRange")) { return true; } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 2b6513a7a0f..9cf778f138a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -2,7 +2,6 @@ package org.jetbrains.jet.codegen; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; -import jet.Function1; import jet.JetObject; import jet.typeinfo.TypeInfo; import jet.typeinfo.TypeInfoProjection; @@ -58,6 +57,8 @@ public class JetTypeMapper { private final HashMap knowTypes = new HashMap(); public static final Type TYPE_FUNCTION1 = Type.getObjectType("jet/Function1"); + public static final Type TYPE_ITERATOR = Type.getObjectType("jet/Iterator"); + public static final Type TYPE_INT_RANGE = Type.getObjectType("jet/IntRange"); public JetTypeMapper(JetStandardLibrary standardLibrary, BindingContext bindingContext) { this.standardLibrary = standardLibrary; @@ -464,17 +465,16 @@ public class JetTypeMapper { } - private Method mapSignature(JetNamedFunction f, List valueParameterTypes, OwnerKind kind) { - final JetTypeReference receiverTypeRef = f.getReceiverTypeRef(); - final JetType receiverType = receiverTypeRef == null ? null : bindingContext.get(BindingContext.TYPE, receiverTypeRef); - final List parameters = f.getValueParameters(); + private Method mapSignature(FunctionDescriptor f, List valueParameterTypes, OwnerKind kind) { + final ReceiverDescriptor receiverTypeRef = f.getReceiver(); + final JetType receiverType = receiverTypeRef == ReceiverDescriptor.NO_RECEIVER ? null : receiverTypeRef.getType(); + final List parameters = f.getValueParameters(); List parameterTypes = new ArrayList(); if (receiverType != null) { parameterTypes.add(mapType(receiverType)); } - FunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, f); if(kind == OwnerKind.TRAIT_IMPL) { - ClassDescriptor containingDeclaration = (ClassDescriptor) functionDescriptor.getContainingDeclaration(); + ClassDescriptor containingDeclaration = (ClassDescriptor) f.getContainingDeclaration(); JetType jetType = TraitImplBodyCodegen.getSuperClass(containingDeclaration, bindingContext); Type type = mapType(jetType); if(type.getInternalName().equals("java/lang/Object")) { @@ -484,24 +484,15 @@ public class JetTypeMapper { valueParameterTypes.add(type); parameterTypes.add(type); } - for (JetParameter parameter : parameters) { - final Type type = mapType(bindingContext.get(BindingContext.TYPE, parameter.getTypeReference())); + for (ValueParameterDescriptor parameter : parameters) { + final Type type = mapType(parameter.getOutType()); valueParameterTypes.add(type); parameterTypes.add(type); } for (int n = f.getTypeParameters().size(); n > 0; n--) { parameterTypes.add(TYPE_TYPEINFO); } - final JetTypeReference returnTypeRef = f.getReturnTypeRef(); - Type returnType; - if (returnTypeRef == null) { - assert functionDescriptor != null; - final JetType type = functionDescriptor.getReturnType(); - returnType = mapReturnType(type); - } - else { - returnType = mapReturnType(bindingContext.get(BindingContext.TYPE, returnTypeRef)); - } + Type returnType = mapReturnType(f.getReturnType()); return new Method(f.getName(), returnType, parameterTypes.toArray(new Type[parameterTypes.size()])); } @@ -515,9 +506,13 @@ public class JetTypeMapper { JetNamedFunction f = (JetNamedFunction) declaration; final FunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, f); assert functionDescriptor != null; + return mapToCallableMethod(functionDescriptor, kind); + } + + public CallableMethod mapToCallableMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) { final DeclarationDescriptor functionParent = functionDescriptor.getContainingDeclaration(); final List valueParameterTypes = new ArrayList(); - Method descriptor = mapSignature(f, valueParameterTypes, kind); + Method descriptor = mapSignature(functionDescriptor.getOriginal(), valueParameterTypes, kind); String owner; int invokeOpcode; boolean needsReceiver; @@ -525,7 +520,7 @@ public class JetTypeMapper { if (functionParent instanceof NamespaceDescriptor) { owner = NamespaceCodegen.getJVMClassName(DescriptorRenderer.getFQName(functionParent)); invokeOpcode = Opcodes.INVOKESTATIC; - needsReceiver = f.getReceiverTypeRef() != null; + needsReceiver = functionDescriptor.getReceiver() != ReceiverDescriptor.NO_RECEIVER; } else if (functionParent instanceof ClassDescriptor) { ClassDescriptor containingClass = (ClassDescriptor) functionParent; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java index 7a7c280f8e1..f60fc9804cc 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java @@ -197,6 +197,9 @@ public abstract class StackValue { if (type.getSort() == Type.BOOLEAN) { v.checkcast(JetTypeMapper.JL_BOOLEAN_TYPE); } + else if (type.getSort() == Type.CHAR) { + v.checkcast(JetTypeMapper.JL_CHAR_TYPE); + } else { v.checkcast(JetTypeMapper.JL_NUMBER_TYPE); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIndices.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIndices.java new file mode 100644 index 00000000000..4049e238e43 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIndices.java @@ -0,0 +1,21 @@ +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; + +public class ArrayIndices implements IntrinsicMethod { + @Override + public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { + receiver.put(JetTypeMapper.TYPE_OBJECT, v); + v.arraylength(); + v.invokestatic("jet/IntRange", "count", "(I)Ljet/IntRange;"); + return StackValue.onStack(JetTypeMapper.TYPE_INT_RANGE); + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIterator.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIterator.java new file mode 100644 index 00000000000..c61130a7b15 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIterator.java @@ -0,0 +1,65 @@ +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.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.psi.JetCallExpression; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.types.JetStandardLibrary; +import org.jetbrains.jet.lang.types.JetType; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.InstructionAdapter; + +import java.util.List; + +/** + * @author alex.tkachman + */ +public class ArrayIterator implements IntrinsicMethod { + @Override + public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { + receiver.put(JetTypeMapper.TYPE_OBJECT, v); + JetCallExpression call = (JetCallExpression) element; + FunctionDescriptor funDescriptor = (FunctionDescriptor) codegen.getBindingContext().get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) call.getCalleeExpression()); + ClassDescriptor containingDeclaration = (ClassDescriptor) funDescriptor.getContainingDeclaration().getOriginal(); + JetStandardLibrary standardLibrary = codegen.getState().getStandardLibrary(); + if(containingDeclaration.equals(standardLibrary.getArray())) { + codegen.generateTypeInfo(funDescriptor.getReturnType().getArguments().get(0).getType()); + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([Ljava/lang/Object;Ljet/typeinfo/TypeInfo;)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getByteArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([B)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getShortArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([S)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getIntArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([I)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getLongArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([J)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getFloatArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([F)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getDoubleArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([D)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getCharArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([C)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getBooleanArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([Z)Ljet/Iterator;"); + } + else { + throw new UnsupportedOperationException(containingDeclaration.toString()); + } + return StackValue.onStack(JetTypeMapper.TYPE_ITERATOR); + } +} 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 ce4c0e29b46..b1efba96116 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java @@ -29,11 +29,13 @@ public class IntrinsicMethods { private static final IntrinsicMethod DEC = new Increment(-1); private static final List PRIMITIVE_NUMBER_TYPES = ImmutableList.of("Boolean", "Byte", "Char", "Short", "Int", "Float", "Long", "Double"); - public static final ArraySize ARRAY_SIZE = new ArraySize(); + public static final IntrinsicMethod ARRAY_SIZE = new ArraySize(); + public static final IntrinsicMethod ARRAY_INDICES = new ArrayIndices(); private final Project myProject; private final JetStandardLibrary myStdLib; private final Map myMethods = new HashMap(); + private static final IntrinsicMethod ARRAY_ITERATOR = new ArrayIterator(); public IntrinsicMethods(Project project, JetStandardLibrary stdlib) { myProject = project; @@ -87,6 +89,30 @@ public class IntrinsicMethods { declareIntrinsicProperty("DoubleArray", "size", ARRAY_SIZE); declareIntrinsicProperty("CharArray", "size", ARRAY_SIZE); declareIntrinsicProperty("BooleanArray", "size", ARRAY_SIZE); + + declareIntrinsicProperty("Array", "indices", ARRAY_INDICES); + declareIntrinsicProperty("ByteArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("ShortArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("IntArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("LongArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("FloatArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("DoubleArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("CharArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("BooleanArray", "indices", ARRAY_INDICES); + + declareIterator(myStdLib.getArray()); + declareIterator(myStdLib.getByteArrayClass()); + declareIterator(myStdLib.getShortArrayClass()); + declareIterator(myStdLib.getIntArrayClass()); + declareIterator(myStdLib.getLongArrayClass()); + declareIterator(myStdLib.getFloatArrayClass()); + declareIterator(myStdLib.getDoubleArrayClass()); + declareIterator(myStdLib.getCharArrayClass()); + declareIterator(myStdLib.getBooleanArrayClass()); + } + + private void declareIterator(ClassDescriptor classDescriptor) { + declareOverload(classDescriptor.getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); } private void declareIntrinsicStringMethods() { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/RangeTo.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/RangeTo.java index 79953a13b0f..86850d21051 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/RangeTo.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/RangeTo.java @@ -16,21 +16,15 @@ import java.util.List; * @author yole */ public class RangeTo implements IntrinsicMethod { - private static final String INT_RANGE_CONSTRUCTOR_DESCRIPTOR = "(II)V"; - private static final Type INT_RANGE_TYPE = Type.getType(IntRange.class); - private static final String CLASS_INT_RANGE = "jet/IntRange"; - @Override public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { JetBinaryExpression expression = (JetBinaryExpression) element; final Type leftType = codegen.expressionType(expression.getLeft()); if (JetTypeMapper.isIntPrimitive(leftType)) { - v.anew(INT_RANGE_TYPE); - v.dup(); codegen.gen(expression.getLeft(), Type.INT_TYPE); codegen.gen(expression.getRight(), Type.INT_TYPE); - v.invokespecial(CLASS_INT_RANGE, "", INT_RANGE_CONSTRUCTOR_DESCRIPTOR); - return StackValue.onStack(INT_RANGE_TYPE); + v.invokestatic("jet/IntRange", "rangeTo", "(II)Ljet/IntRange;"); + return StackValue.onStack(JetTypeMapper.TYPE_INT_RANGE); } else { throw new UnsupportedOperationException("ranges are only supported for int objects"); diff --git a/compiler/frontend/src/jet/Library.jet b/compiler/frontend/src/jet/Library.jet index f11575b99d3..0a57bbf4c91 100644 --- a/compiler/frontend/src/jet/Library.jet +++ b/compiler/frontend/src/jet/Library.jet @@ -42,7 +42,7 @@ fun Any?.toString() : String// = this === other trait Iterator { fun next() : T - abstract fun hasNext() : Boolean + fun hasNext() : Boolean } trait Iterable { @@ -54,6 +54,8 @@ class Array(val size : Int, init : fun(Int) : T = null ) { fun set(index : Int, value : T) : Unit fun iterator() : Iterator + + val indices : IntRange } class ByteArray(val size : Int) { @@ -61,6 +63,8 @@ class ByteArray(val size : Int) { fun set(index : Int, value : Byte) : Unit fun iterator() : Iterator + + val indices : IntRange } class ShortArray(val size : Int) { @@ -68,6 +72,8 @@ class ShortArray(val size : Int) { fun set(index : Int, value : Short) : Unit fun iterator() : Iterator + + val indices : IntRange } class IntArray(val size : Int) { @@ -75,6 +81,8 @@ class IntArray(val size : Int) { fun set(index : Int, value : Int) : Unit fun iterator() : Iterator + + val indices : IntRange } class LongArray(val size : Int) { @@ -82,6 +90,8 @@ class LongArray(val size : Int) { fun set(index : Int, value : Long) : Unit fun iterator() : Iterator + + val indices : IntRange } class FloatArray(val size : Int) { @@ -89,6 +99,8 @@ class FloatArray(val size : Int) { fun set(index : Int, value : Float) : Unit fun iterator() : Iterator + + val indices : IntRange } class DoubleArray(val size : Int) { @@ -96,6 +108,8 @@ class DoubleArray(val size : Int) { fun set(index : Int, value : Double) : Unit fun iterator() : Iterator + + val indices : IntRange } class CharArray(val size : Int) { @@ -103,6 +117,8 @@ class CharArray(val size : Int) { fun set(index : Int, value : Char) : Unit fun iterator() : Iterator + + val indices : IntRange } class BooleanArray(val size : Int) { @@ -110,6 +126,8 @@ class BooleanArray(val size : Int) { fun set(index : Int, value : Boolean) : Unit fun iterator() : Iterator + + val indices : IntRange } trait Comparable { @@ -152,8 +170,28 @@ trait Range> { fun contains(item : T) : Boolean } -class IntRange>(val start : Int, val end : Int) : Range, Iterable { +class IntRange(val start : Int, size : Int, reversed : Boolean = false) : Range, Iterable { + fun iterator () : Iterator + fun contains (elem: Int) : Boolean + + val size : Int + + val end : Int + + val reversed : Boolean +} + +class LongRange(val start : Long, size : Long, reversed : Boolean = false) : Range, Iterable { + fun iterator () : Iterator + + fun contains (elem: Long) : Boolean + + val size : Long + + val end : Long + + val reversed : Boolean } abstract class Number : Hashable { @@ -349,11 +387,11 @@ class Long : Number, Comparable { fun rangeTo(other : Double) : Range fun rangeTo(other : Float) : Range - fun rangeTo(other : Long) : IntRange - fun rangeTo(other : Int) : IntRange - fun rangeTo(other : Short) : IntRange - fun rangeTo(other : Byte) : IntRange - fun rangeTo(other : Char) : IntRange + fun rangeTo(other : Long) : LongRange + fun rangeTo(other : Int) : LongRange + fun rangeTo(other : Short) : LongRange + fun rangeTo(other : Byte) : LongRange + fun rangeTo(other : Char) : LongRange fun inc() : Long fun dec() : Long @@ -420,11 +458,11 @@ class Int : Number, Comparable { fun rangeTo(other : Double) : Range fun rangeTo(other : Float) : Range - fun rangeTo(other : Long) : IntRange - fun rangeTo(other : Int) : IntRange - fun rangeTo(other : Short) : IntRange - fun rangeTo(other : Byte) : IntRange - fun rangeTo(other : Char) : IntRange + fun rangeTo(other : Long) : LongRange + fun rangeTo(other : Int) : IntRange + fun rangeTo(other : Short) : IntRange + fun rangeTo(other : Byte) : IntRange + fun rangeTo(other : Char) : IntRange fun inc() : Int fun dec() : Int @@ -491,11 +529,11 @@ class Char : Number, Comparable { fun rangeTo(other : Double) : Range fun rangeTo(other : Float) : Range - fun rangeTo(other : Long) : IntRange - fun rangeTo(other : Int) : IntRange - fun rangeTo(other : Short) : IntRange - fun rangeTo(other : Byte) : IntRange - fun rangeTo(other : Char) : IntRange + fun rangeTo(other : Long) : LongRange + fun rangeTo(other : Int) : IntRange + fun rangeTo(other : Short) : IntRange + fun rangeTo(other : Byte) : IntRange + fun rangeTo(other : Char) : IntRange fun inc() : Char fun dec() : Char @@ -554,11 +592,11 @@ class Short : Number, Comparable { fun rangeTo(other : Double) : Range fun rangeTo(other : Float) : Range - fun rangeTo(other : Long) : IntRange - fun rangeTo(other : Int) : IntRange - fun rangeTo(other : Short) : IntRange - fun rangeTo(other : Byte) : IntRange - fun rangeTo(other : Char) : IntRange + fun rangeTo(other : Long) : LongRange + fun rangeTo(other : Int) : IntRange + fun rangeTo(other : Short) : IntRange + fun rangeTo(other : Byte) : IntRange + fun rangeTo(other : Char) : IntRange fun inc() : Short fun dec() : Short @@ -617,11 +655,11 @@ class Byte : Number, Comparable { fun rangeTo(other : Double) : Range fun rangeTo(other : Float) : Range - fun rangeTo(other : Long) : IntRange - fun rangeTo(other : Int) : IntRange - fun rangeTo(other : Short) : IntRange - fun rangeTo(other : Byte) : IntRange - fun rangeTo(other : Char) : IntRange + fun rangeTo(other : Long) : LongRange + fun rangeTo(other : Int) : IntRange + fun rangeTo(other : Short) : IntRange + fun rangeTo(other : Byte) : IntRange + fun rangeTo(other : Char) : IntRange fun inc() : Byte fun dec() : Byte diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java index 2036d25cafb..6029d19c358 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java @@ -312,8 +312,7 @@ public class JetStandardLibrary { @NotNull public JetType getArrayType(@NotNull JetType argument) { - Variance variance = Variance.INVARIANT; - return getArrayType(variance, argument); + return getArrayType(Variance.INVARIANT, argument); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index d188f7e43b4..05c1ff314f3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -456,6 +456,9 @@ public class JetTypeInferrer { } else { result = blockLevelVisitor.getType(statementExpression, newContext); + if (coercionStrategyForLastExpression == CoercionStrategy.COERCION_TO_UNIT && result == null) { + result = JetStandardClasses.getUnitType(); + } } DataFlowInfo newDataFlowInfo = blockLevelVisitor.getResultingDataFlowInfo(); @@ -1020,6 +1023,7 @@ public class JetTypeInferrer { if (functionTypeExpected) { JetType expectedReturnType = JetStandardClasses.getReturnType(expectedType); + functionDescriptor.setReturnType(expectedReturnType); if (JetStandardClasses.isUnit(expectedReturnType)) { return context.services.checkType(JetStandardClasses.getFunctionType(Collections.emptyList(), effectiveReceiverType, parameterTypes, expectedReturnType), expression, context); } diff --git a/idea/testData/codegen/regressions/kt343.jet b/idea/testData/codegen/regressions/kt343.jet new file mode 100644 index 00000000000..36b922c3f51 --- /dev/null +++ b/idea/testData/codegen/regressions/kt343.jet @@ -0,0 +1,16 @@ +import java.util.ArrayList + +fun box(): String { + val list = ArrayList() + val foo : fun() : Unit = { + list.add(2) //first exception + } + foo() + + val bar = { + val x = 1 //second exception + } + bar() + + return if (list.get(0) == 2) "OK" else "fail" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java b/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java index dcd5e4d9783..a7aa2572f54 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java @@ -58,4 +58,46 @@ public class ArrayGenTest extends CodegenTestCase { System.out.println(invoke.getClass()); assertTrue(invoke instanceof Integer); } + + public void testIterator () throws Exception { + loadText("fun box() { val x = Array(5, { it } ).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } + + public void testPrimitiveIterator () 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 testLongIterator () 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 testCharIterator () throws Exception { + loadText("fun box() { val x = CharArray(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()); + Method foo = generateFunction(); + foo.invoke(null); + } + + public void testCharIndices () throws Exception { + loadText("fun box() { val x = CharArray(5).indices.iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } } diff --git a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java index 17e5d4f9252..72a131c61c6 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -185,4 +185,9 @@ public class ClassGenTest extends CodegenTestCase { assertEquals(method.getReturnType().getName(), "java.lang.Object"); System.out.println(generateToText()); } + + public void testKt343 () throws Exception { + blackBoxFile("regressions/kt343.jet"); + System.out.println(generateToText()); + } } diff --git a/stdlib/src/jet/IntRange.java b/stdlib/src/jet/IntRange.java index dc538cddc4b..abeb2a0f696 100644 --- a/stdlib/src/jet/IntRange.java +++ b/stdlib/src/jet/IntRange.java @@ -1,28 +1,99 @@ package jet; -public class IntRange implements Range { - private final int startValue; - private final int endValue; +import jet.typeinfo.TypeInfo; - public IntRange(int startValue, int endValue) { - this.startValue = startValue; - this.endValue = endValue; +public final class IntRange implements Range, Iterable, JetObject { + private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(IntRange.class, false); + + private final int start; + private final int count; + + public IntRange(int startValue, int count) { + this.start = startValue; + this.count = count; + } + + public IntRange(int startValue, int count, boolean reversed) { + this(startValue, reversed ? -count : count); } @Override public boolean contains(Integer item) { if (item == null) return false; - if (startValue <= endValue) { - return item >= startValue && item <= endValue; + if (count >= 0) { + return item >= start && item < start + count; } - return item <= startValue && item >= endValue; + return item <= start && item > start + count; } - public int getStartValue() { - return startValue; + public int getStart() { + return start; } - public int getEndValue() { - return endValue; + public int getEnd() { + return start+count-1; + } + + public int getSize() { + return count < 0 ? -count : count; + } + + @Override + public Iterator iterator() { + return new MyIterator(start, count); + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + + public static IntRange count(int length) { + return new IntRange(0, length); + } + + public static IntRange rangeTo(int from, int to) { + if(from > to) { + return new IntRange(to, from-to+1, true); + } + else { + return new IntRange(from, to-from+1); + } + } + + private static class MyIterator implements Iterator { + private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(MyIterator.class, false); + + private int cur; + private int count; + + private final boolean reversed; + + public MyIterator(int startValue, int count) { + cur = startValue; + reversed = count < 0; + this.count = reversed ? -count : count; + } + + @Override + public boolean hasNext() { + return count > 0; + } + + @Override + public Integer next() { + count--; + if(reversed) { + return cur--; + } + else { + return cur++; + } + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } } } diff --git a/stdlib/src/jet/LongRange.java b/stdlib/src/jet/LongRange.java new file mode 100644 index 00000000000..7932f7d0b5d --- /dev/null +++ b/stdlib/src/jet/LongRange.java @@ -0,0 +1,99 @@ +package jet; + +import jet.typeinfo.TypeInfo; + +public final class LongRange implements Range, Iterable, JetObject { + private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(IntRange.class, false); + + private final long start; + private final long count; + + public LongRange(long startValue, long count) { + this.start = startValue; + this.count = count; + } + + public LongRange(long startValue, long count, boolean reversed) { + this(startValue, reversed ? -count : count); + } + + @Override + public boolean contains(Long item) { + if (item == null) return false; + if (count >= 0) { + return item >= start && item < start + count; + } + return item <= start && item > start + count; + } + + public long getStart() { + return start; + } + + public long getEnd() { + return start+count-1; + } + + public long getSize() { + return count < 0 ? -count : count; + } + + @Override + public Iterator iterator() { + return new MyIterator(start, count); + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + + public static IntRange count(int length) { + return new IntRange(0, length); + } + + public static IntRange rangeTo(int from, int to) { + if(from > to) { + return new IntRange(to, from-to+1, true); + } + else { + return new IntRange(from, to-from+1); + } + } + + private static class MyIterator implements Iterator { + private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(MyIterator.class, false); + + private long cur; + private long count; + + private final boolean reversed; + + public MyIterator(long startValue, long count) { + cur = startValue; + reversed = count < 0; + this.count = reversed ? -count : count; + } + + @Override + public boolean hasNext() { + return count > 0; + } + + @Override + public Long next() { + count--; + if(reversed) { + return cur--; + } + else { + return cur++; + } + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + } +} diff --git a/stdlib/src/jet/arrays/ArrayIterator.java b/stdlib/src/jet/arrays/ArrayIterator.java new file mode 100644 index 00000000000..3bbfac045f3 --- /dev/null +++ b/stdlib/src/jet/arrays/ArrayIterator.java @@ -0,0 +1,274 @@ +package jet.arrays; + +import jet.Iterator; +import jet.typeinfo.TypeInfo; +import jet.typeinfo.TypeInfoProjection; + +import java.lang.reflect.GenericArrayType; +import java.util.Arrays; + +/** + * @author alex.tkachman + */ +public abstract class ArrayIterator implements Iterator { + private final int size; + protected int index; + + protected ArrayIterator(int size) { + this.size = size; + } + + @Override + public boolean hasNext() { + return index < size; + } + + private static class GenericIterator extends ArrayIterator { + private final T[] array; + private final TypeInfo elementTypeInfo; + + private GenericIterator(T[] array, TypeInfo elementTypeInfo) { + super(array.length); + this.array = array; + this.elementTypeInfo = elementTypeInfo; + } + + @Override + public T next() { + return array[index++]; + } + + @Override + public TypeInfo getTypeInfo() { + return TypeInfo.getTypeInfo(GenericIterator.class, false, null, new TypeInfoProjection[] {(TypeInfoProjection) elementTypeInfo}); + } + } + + public static Iterator iterator(T[] array, TypeInfo elementTypeInfo) { + return new GenericIterator(array, elementTypeInfo); + } + + private static class ByteIterator extends ArrayIterator { + private final byte[] array; + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(ByteIterator.class, false); + + private ByteIterator(byte[] array) { + super(array.length); + this.array = array; + } + + @Override + public Byte next() { + return array[index++]; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + } + + public static Iterator iterator(byte[] array) { + return new ByteIterator(array); + } + + private static class ShortIterator extends ArrayIterator { + private final short[] array; + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(ShortIterator.class, false); + + private ShortIterator(short[] array) { + super(array.length); + this.array = array; + } + + @Override + public Short next() { + return array[index++]; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + } + + public static Iterator iterator(short[] array) { + return new ShortIterator(array); + } + + private static class IntegerIterator extends ArrayIterator { + private final int[] array; + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(IntegerIterator.class, false); + + private IntegerIterator(int[] array) { + super(array.length); + this.array = array; + } + + @Override + public Integer next() { + return array[index++]; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + } + + public static Iterator iterator(int[] array) { + return new IntegerIterator(array); + } + + private static class LongIterator extends ArrayIterator { + private final long[] array; + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(LongIterator.class, false); + + private LongIterator(long[] array) { + super(array.length); + this.array = array; + } + + @Override + public Long next() { + return array[index++]; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + } + + public static Iterator iterator(long[] array) { + return new LongIterator(array); + } + + private static class FloatIterator extends ArrayIterator { + private final float[] array; + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(FloatIterator.class, false); + + private FloatIterator(float[] array) { + super(array.length); + this.array = array; + } + + @Override + public Float next() { + return array[index++]; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + } + + public static Iterator iterator(float[] array) { + return new FloatIterator(array); + } + + private static class DoubleIterator extends ArrayIterator { + private final double[] array; + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(DoubleIterator.class, false); + + private DoubleIterator(double[] array) { + super(array.length); + this.array = array; + } + + @Override + public Double next() { + return array[index++]; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + } + + public static Iterator iterator(double[] array) { + return new DoubleIterator(array); + } + + private static class CharacterIterator extends ArrayIterator { + private final char[] array; + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(CharacterIterator.class, false); + + private CharacterIterator(char[] array) { + super(array.length); + this.array = array; + } + + @Override + public Character next() { + return array[index++]; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + } + + public static Iterator iterator(char[] array) { + return new CharacterIterator(array); + } + + private static class BooleanIterator extends ArrayIterator { + private final boolean[] array; + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(BooleanIterator.class, false); + + private BooleanIterator(boolean[] array) { + super(array.length); + this.array = array; + } + + @Override + public Boolean next() { + return array[index++]; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + } + + public static Iterator iterator(boolean[] array) { + return new BooleanIterator(array); + } + + public static void main(String[] args) { + String[] strings = {"Byte", "byte", "Short", "short", "Integer", "int", "Long", "long", "Float", "float", "Double", "double", "Character", "char", "Boolean", "boolean"}; + for(int i = 0; i != strings.length; i += 2) { + String boxed = strings[i]; + String unboxed = strings[i+1]; + System.out.println(" private static class " + boxed + "Iterator extends ArrayIterator<" + boxed + "> {\n" + + " private final " + unboxed + "[] array;\n" + + " private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(" + boxed + "Iterator.class, false);\n" + + "\n" + + " private " + boxed + "Iterator(" + unboxed + "[] array) {\n" + + " super(array.length);\n" + + " this.array = array;\n" + + " }\n" + + "\n" + + " @Override\n" + + " public " + boxed + " next() {\n" + + " return array[index++];\n" + + " }\n" + + "\n" + + " @Override\n" + + " public TypeInfo getTypeInfo() {\n" + + " return typeInfo;\n" + + " }\n" + + " }\n" + + "\n" + + " public static Iterator<" + boxed + "> iterator(" + unboxed + "[] array) {\n" + + " return new " + boxed + "Iterator(array);\n" + + " }\n" + + ""); + } + } +}