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 ac46bd31b60..c742cd0d633 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/RangeTo.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/RangeTo.java @@ -30,7 +30,7 @@ public class RangeTo implements IntrinsicMethod { if (JetTypeMapper.isIntPrimitive(leftType)) { codegen.gen(expression.getLeft(), Type.INT_TYPE); codegen.gen(expression.getRight(), Type.INT_TYPE); - v.invokestatic("jet/IntRange", "rangeTo", "(II)Ljet/IntRange;"); + v.invokestatic(expectedType.getInternalName(), "rangeTo", "(" + leftType.getDescriptor() + leftType.getDescriptor() + ")" + expectedType.getDescriptor()); return StackValue.onStack(JetTypeMapper.TYPE_INT_RANGE); } else { diff --git a/compiler/frontend/src/jet/Library.jet b/compiler/frontend/src/jet/Library.jet index 292e05dcf2a..48e139cbb96 100644 --- a/compiler/frontend/src/jet/Library.jet +++ b/compiler/frontend/src/jet/Library.jet @@ -238,28 +238,64 @@ trait Range> { fun contains(item : T) : Boolean } -class IntRange(val start : Int, size : Int, reversed : Boolean = false) : Range, IntIterable { - fun iterator () : Iterator +class IntRange(val start : Int, val size : Int, val isReversed : Boolean = false) : Range, IntIterable { + fun iterator () : IntIterator fun contains (elem: Int) : Boolean - val size : Int - val end : Int - val reversed : Boolean + fun minus() : IntRange + + fun step(step: Int) : IntIterable } -class LongRange(val start : Long, size : Long, reversed : Boolean = false) : Range, Iterable { - fun iterator () : Iterator +class LongRange(val start : Long, val size : Long, val isReversed : Boolean = false) : Range, LongIterable { + fun iterator () : LongIterator fun contains (elem: Long) : Boolean - val size : Long - val end : Long - val reversed : Boolean + fun minus() : LongRange + + fun step(step: Long) : LongIterable +} + +class ByteRange(val start : Byte, val size : Int, val isReversed : Boolean = false) : Range, ByteIterable { + fun iterator () : ByteIterator + + fun contains (elem: Byte) : Boolean + + val end : Byte + + fun minus() : ByteRange + + fun step(step: Int) : ByteIterable +} + +class ShortRange(val start : Short, val size : Int, val isReversed : Boolean = false) : Range, ShortIterable { + fun iterator () : ShortIterator + + fun contains (elem: Byte) : Boolean + + val end : Short + + fun minus() : ShortRange + + fun step(step: Int) : ShortIterable +} + +class CharRange(val start : Char, val size : Int, val isReversed : Boolean = false) : Range, CharIterable { + fun iterator () : CharIterator + + fun contains (elem: Char) : Boolean + + val end : Char + + fun minus() : CharRange + + fun step(step: Int) : CharIterable } abstract class Number : Hashable { @@ -601,7 +637,7 @@ class Char : Number, Comparable { fun rangeTo(other : Int) : IntRange fun rangeTo(other : Short) : IntRange fun rangeTo(other : Byte) : IntRange - fun rangeTo(other : Char) : IntRange + fun rangeTo(other : Char) : CharRange fun inc() : Char fun dec() : Char @@ -662,8 +698,8 @@ class Short : Number, Comparable { fun rangeTo(other : Float) : Range fun rangeTo(other : Long) : LongRange fun rangeTo(other : Int) : IntRange - fun rangeTo(other : Short) : IntRange - fun rangeTo(other : Byte) : IntRange + fun rangeTo(other : Short) : ShortRange + fun rangeTo(other : Byte) : ShortRange fun rangeTo(other : Char) : IntRange fun inc() : Short @@ -725,8 +761,8 @@ class Byte : Number, Comparable { fun rangeTo(other : Float) : Range fun rangeTo(other : Long) : LongRange fun rangeTo(other : Int) : IntRange - fun rangeTo(other : Short) : IntRange - fun rangeTo(other : Byte) : IntRange + fun rangeTo(other : Short) : ShortRange + fun rangeTo(other : Byte) : ByteRange fun rangeTo(other : Char) : IntRange fun inc() : Byte diff --git a/compiler/testData/codegen/regressions/kt821.kt b/compiler/testData/codegen/regressions/kt821.kt new file mode 100644 index 00000000000..c9eea791ac6 --- /dev/null +++ b/compiler/testData/codegen/regressions/kt821.kt @@ -0,0 +1,51 @@ +fun box() : String { + val r1 = IntRange(1, 4) + if(r1.end != 4 || r1.isReversed || r1.size != 4) return "fail" + + val r2 = IntRange(1, 4, true) + if(r2.end != -2 || !r2.isReversed || r2.size != 4) return "fail" + + val r3 = -(0..5) + if(r3.start != 5 || r3.end != 0 || !r3.isReversed || r3.size != 6) return "fail" + + val r4 = -r3 + if(r4.end != 5 || r4.isReversed || r4.size != 6) return "fail" + + val r5 = ByteRange(1, 4) + if(r5.end != 4.byt || r5.isReversed || r5.size != 4) return "fail" + + val r6 = ByteRange(1, 4, true) + if(r6.end != -2.byt || !r6.isReversed) return "fail" + + val r7 = -(0.byt..5.byt) + if(r7.start != 5.byt || r7.end != 0.byt || !r7.isReversed) return "fail" + + val r9 = -r7 + if(r9.end != 5.byt || r9.isReversed) return "fail" + + val r10 = ShortRange(1, 4) + if(r10.end != 4.sht || r10.isReversed || r10.size != 4) return "fail" + + val r11 = ShortRange(1, 4, true) + if(r11.end != -2.sht || !r11.isReversed) return "fail" + + val r12 = -(0.sht..5.sht) + if(r12.start != 5.sht || r12.end != 0.sht || !r12.isReversed) return "fail" + + val r13 = -r12 + if(r13.end != 5.sht || r13.isReversed) return "fail" + + val r14 = CharRange('a', 4) + if(r14.end != 'd' || r14.isReversed || r14.size != 4) return "fail" + + val r15 = CharRange('D', 4, true) + if(r15.end != 'A' || !r15.isReversed) return "fail" + + val r16 = -('a'..'e') + if(r16.start != 'e' || r16.end != 'a' || !r16.isReversed) return "fail" + + val r17 = -r16 + if(r17.end != 'e' || r17.isReversed) return "fail" + + return "OK" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java b/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java index 51954800c69..6275a968154 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java @@ -363,4 +363,8 @@ public class PrimitiveTypesTest extends CodegenTestCase { public void testKt887 () { blackBoxFile("regressions/kt887.jet"); } + + public void testKt821 () { + blackBoxFile("regressions/kt821.kt"); + } } diff --git a/stdlib/src/jet/ByteRange.java b/stdlib/src/jet/ByteRange.java new file mode 100644 index 00000000000..754445a4459 --- /dev/null +++ b/stdlib/src/jet/ByteRange.java @@ -0,0 +1,119 @@ +package jet; + +public final class ByteRange implements Range, ByteIterable, JetObject { + private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(ByteRange.class, false); + + private final byte start; + private final int count; + + public ByteRange(byte startValue, int count) { + this.start = startValue; + this.count = count; + } + + public ByteRange(byte startValue, int count, boolean reversed) { + this(startValue, reversed ? -count : count); + } + + public ByteRange(byte startValue, int count, boolean reversed, int defaultMask) { + this(startValue, reversed ? -count : count, (defaultMask & 4) == 0); + } + + @Override + public boolean contains(Byte item) { + if (item == null) return false; + if (count >= 0) { + return item >= start && item < start + count; + } + return item <= start && item > start + count; + } + + public boolean getIsReversed() { + return count < 0; + } + + public byte getStart() { + return start; + } + + public byte getEnd() { + return (byte) (count < 0 ? start + count + 1: start+count-1); + } + + public int getSize() { + return count < 0 ? -count : count; + } + + public ByteRange minus() { + return new ByteRange(getEnd(), -count); + } + + @Override + public ByteIterator iterator() { + return new MyIterator(start, count); + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + + @Override + public JetObject getOuterObject() { + return null; + } + + public static ByteRange count(int length) { + return new ByteRange((byte) 0, length); + } + + public static ByteRange rangeTo(byte from, byte to) { + if(from > to) { + return new ByteRange(to, from-to+1, true); + } + else { + return new ByteRange(from, to-from+1); + } + } + + private static class MyIterator extends ByteIterator { + private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(MyIterator.class, false); + + private byte cur; + private int count; + + private final boolean reversed; + + public MyIterator(byte startValue, int count) { + cur = startValue; + reversed = count < 0; + this.count = reversed ? -count : count; + } + + @Override + public boolean getHasNext() { + return count > 0; + } + + @Override + public byte nextByte() { + count--; + if(reversed) { + return cur--; + } + else { + return cur++; + } + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + + @Override + public JetObject getOuterObject() { + return null; + } + } +} diff --git a/stdlib/src/jet/CharRange.java b/stdlib/src/jet/CharRange.java new file mode 100644 index 00000000000..e295795527e --- /dev/null +++ b/stdlib/src/jet/CharRange.java @@ -0,0 +1,119 @@ +package jet; + +public final class CharRange implements Range, CharIterable, JetObject { + private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(CharRange.class, false); + + private final char start; + private final int count; + + public CharRange(char startValue, int count) { + this.start = startValue; + this.count = count; + } + + public CharRange(char startValue, int count, boolean reversed) { + this(startValue, reversed ? -count : count); + } + + public CharRange(char startValue, int count, boolean reversed, int defaultMask) { + this(startValue, reversed ? -count : count, (defaultMask & 4) == 0); + } + + @Override + public boolean contains(Character item) { + if (item == null) return false; + if (count >= 0) { + return item >= start && item < start + count; + } + return item <= start && item > start + count; + } + + public boolean getIsReversed() { + return count < 0; + } + + public char getStart() { + return start; + } + + public char getEnd() { + return (char) (count < 0 ? start + count + 1: start+count-1); + } + + public int getSize() { + return count < 0 ? -count : count; + } + + public CharRange minus() { + return new CharRange(getEnd(), -count); + } + + @Override + public CharIterator iterator() { + return new MyIterator(start, count); + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + + @Override + public JetObject getOuterObject() { + return null; + } + + public static CharRange count(int length) { + return new CharRange((char) 0, length); + } + + public static CharRange rangeTo(char from, char to) { + if(from > to) { + return new CharRange(to, from-to+1, true); + } + else { + return new CharRange(from, to-from+1); + } + } + + private static class MyIterator extends CharIterator { + private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(MyIterator.class, false); + + private char cur; + private int count; + + private final boolean reversed; + + public MyIterator(char startValue, int count) { + cur = startValue; + reversed = count < 0; + this.count = reversed ? -count : count; + } + + @Override + public boolean getHasNext() { + return count > 0; + } + + @Override + public char nextChar() { + count--; + if(reversed) { + return cur--; + } + else { + return cur++; + } + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + + @Override + public JetObject getOuterObject() { + return null; + } + } +} diff --git a/stdlib/src/jet/IntRange.java b/stdlib/src/jet/IntRange.java index 2fa3d5f422d..646a095e842 100644 --- a/stdlib/src/jet/IntRange.java +++ b/stdlib/src/jet/IntRange.java @@ -15,6 +15,10 @@ public final class IntRange implements Range, IntIterable, JetObject { this(startValue, reversed ? -count : count); } + public IntRange(int startValue, int count, boolean reversed, int defaultMask) { + this(startValue, reversed ? -count : count, (defaultMask & 4) == 0); + } + @Override public boolean contains(Integer item) { if (item == null) return false; @@ -24,18 +28,26 @@ public final class IntRange implements Range, IntIterable, JetObject { return item <= start && item > start + count; } + public boolean getIsReversed() { + return count < 0; + } + public int getStart() { return start; } public int getEnd() { - return start+count-1; + return count < 0 ? start + count + 1: start+count-1; } public int getSize() { return count < 0 ? -count : count; } + public IntRange minus() { + return new IntRange(getEnd(), -count); + } + @Override public IntIterator iterator() { return new MyIterator(start, count); diff --git a/stdlib/src/jet/LongRange.java b/stdlib/src/jet/LongRange.java index 7f7554c8faf..3a047c7b65f 100644 --- a/stdlib/src/jet/LongRange.java +++ b/stdlib/src/jet/LongRange.java @@ -15,6 +15,10 @@ public final class LongRange implements Range, LongIterable, JetObject { this(startValue, reversed ? -count : count); } + public LongRange(int startValue, int count, boolean reversed, int defaultMask) { + this(startValue, reversed ? -count : count, (defaultMask & 4) == 0); + } + @Override public boolean contains(Long item) { if (item == null) return false; @@ -24,6 +28,10 @@ public final class LongRange implements Range, LongIterable, JetObject { return item <= start && item > start + count; } + public boolean getIsReversed() { + return count < 0; + } + public long getStart() { return start; } @@ -36,6 +44,10 @@ public final class LongRange implements Range, LongIterable, JetObject { return count < 0 ? -count : count; } + public LongRange minus() { + return new LongRange(getEnd(), -count); + } + @Override public LongIterator iterator() { return new MyIterator(start, count); diff --git a/stdlib/src/jet/ShortRange.java b/stdlib/src/jet/ShortRange.java new file mode 100644 index 00000000000..0d96d652d88 --- /dev/null +++ b/stdlib/src/jet/ShortRange.java @@ -0,0 +1,119 @@ +package jet; + +public final class ShortRange implements Range, ShortIterable, JetObject { + private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(ShortRange.class, false); + + private final short start; + private final int count; + + public ShortRange(short startValue, int count) { + this.start = startValue; + this.count = count; + } + + public ShortRange(short startValue, int count, boolean reversed) { + this(startValue, reversed ? -count : count); + } + + public ShortRange(short startValue, int count, boolean reversed, int defaultMask) { + this(startValue, reversed ? -count : count, (defaultMask & 4) == 0); + } + + @Override + public boolean contains(Short item) { + if (item == null) return false; + if (count >= 0) { + return item >= start && item < start + count; + } + return item <= start && item > start + count; + } + + public boolean getIsReversed() { + return count < 0; + } + + public short getStart() { + return start; + } + + public short getEnd() { + return (short) (count < 0 ? start + count + 1: start+count-1); + } + + public int getSize() { + return count < 0 ? -count : count; + } + + public ShortRange minus() { + return new ShortRange(getEnd(), -count); + } + + @Override + public ShortIterator iterator() { + return new MyIterator(start, count); + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + + @Override + public JetObject getOuterObject() { + return null; + } + + public static ShortRange count(int length) { + return new ShortRange((byte) 0, length); + } + + public static ShortRange rangeTo(short from, short to) { + if(from > to) { + return new ShortRange(to, from-to+1, true); + } + else { + return new ShortRange(from, to-from+1); + } + } + + private static class MyIterator extends ShortIterator { + private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(MyIterator.class, false); + + private short cur; + private int count; + + private final boolean reversed; + + public MyIterator(short startValue, int count) { + cur = startValue; + reversed = count < 0; + this.count = reversed ? -count : count; + } + + @Override + public boolean getHasNext() { + return count > 0; + } + + @Override + public short nextShort() { + count--; + if(reversed) { + return cur--; + } + else { + return cur++; + } + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + + @Override + public JetObject getOuterObject() { + return null; + } + } +}