diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureAnnotator.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureAnnotator.java index 83863901f75..aa76f53a2f4 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureAnnotator.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureAnnotator.java @@ -30,6 +30,8 @@ import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.types.lang.JetStandardClasses; +import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; +import org.jetbrains.jet.lang.types.lang.PrimitiveType; import javax.inject.Inject; import java.util.*; @@ -65,6 +67,20 @@ public class ClosureAnnotator { public void init() { mapFilesToNamespaces(files); prepareAnonymousClasses(); + prepareClassObjectsForBuiltinRanges(); + } + + private void prepareClassObjectsForBuiltinRanges() { + // this is needed for range classes because they have class objects with + // intrinsic members + JetScope stdLibraryScope = JetStandardLibrary.getInstance().getLibraryScope(); + for (PrimitiveType type : PrimitiveType.NUMBER_TYPES) { + ClassDescriptor klass = (ClassDescriptor) stdLibraryScope.getClassifier(type.getRangeTypeName()); + String rangeInternalName = JvmClassName.byFqNameWithoutInnerClasses( + JetStandardClasses.STANDARD_CLASSES_FQNAME.child(type.getRangeTypeName())).getInternalName(); + JvmClassName classObjectInternalName = JvmClassName.byInternalName(rangeInternalName + JvmAbi.CLASS_OBJECT_SUFFIX); + classNamesForClassDescriptor.put(klass.getClassObjectDescriptor(), classObjectInternalName); + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/EmptyRange.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/EmptyRange.java new file mode 100644 index 00000000000..0c1d8e86a74 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/EmptyRange.java @@ -0,0 +1,56 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen.intrinsics; + +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.asm4.Type; +import org.jetbrains.asm4.commons.InstructionAdapter; +import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.GenerationState; +import org.jetbrains.jet.codegen.StackValue; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.resolve.java.JvmClassName; +import org.jetbrains.jet.lang.types.lang.PrimitiveType; + +import java.util.List; + +/** + * @author Evgeny Gerashchenko + * @since 08.08.12 + */ +public class EmptyRange implements IntrinsicMethod { + private final PrimitiveType elementType; + + public EmptyRange(PrimitiveType elementType) { + this.elementType = elementType; + } + + @Override + public StackValue generate(ExpressionCodegen codegen, + InstructionAdapter v, + @NotNull Type expectedType, + @Nullable PsiElement element, + @Nullable List arguments, + StackValue receiver, + @NotNull GenerationState state) { + JvmClassName name = JvmClassName.byFqNameWithoutInnerClasses(elementType.getRangeClassName().getFqName()); + v.getstatic(name.toString(), "empty", "L" + name + ";"); + return StackValue.onStack(expectedType); + } +} 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 4aad835fc8f..9a0ca427588 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java @@ -17,7 +17,6 @@ package org.jetbrains.jet.codegen.intrinsics; import com.google.common.collect.ImmutableList; -import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.asm4.Opcodes; @@ -25,6 +24,7 @@ import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.psi.JetPsiUtil; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.java.JvmPrimitiveType; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; @@ -34,7 +34,6 @@ import org.jetbrains.jet.lang.types.lang.JetStandardClasses; import org.jetbrains.jet.lang.types.lang.PrimitiveType; import javax.annotation.PostConstruct; -import javax.inject.Inject; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -141,6 +140,12 @@ public class IntrinsicMethods { declareIntrinsicProperty(Name.identifier("CharSequence"), Name.identifier("length"), new StringLength()); declareIntrinsicProperty(Name.identifier("String"), Name.identifier("length"), new StringLength()); + for (PrimitiveType type : PrimitiveType.NUMBER_TYPES) { + intrinsicsMap.registerIntrinsic( + JetStandardClasses.STANDARD_CLASSES_FQNAME.child(type.getRangeTypeName()).toUnsafe().child(JetPsiUtil.NO_NAME_PROVIDED), + Name.identifier("EMPTY"), -1, new EmptyRange(type)); + } + declareArrayMethods(); } @@ -228,5 +233,4 @@ public class IntrinsicMethods { } return intrinsicMethod; } - } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicsMap.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicsMap.java index c069a0dcee6..631ce95ebf8 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicsMap.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicsMap.java @@ -82,11 +82,18 @@ class IntrinsicsMap { private Map intrinsicsMap = Maps.newHashMap(); + /** + * @param valueParameterCount -1 for property + */ + public void registerIntrinsic(@NotNull FqNameUnsafe owner, @NotNull Name name, int valueParameterCount, @NotNull IntrinsicMethod impl) { + intrinsicsMap.put(new Key(owner, name, valueParameterCount), impl); + } + /** * @param valueParameterCount -1 for property */ public void registerIntrinsic(@NotNull FqName owner, @NotNull Name name, int valueParameterCount, @NotNull IntrinsicMethod impl) { - intrinsicsMap.put(new Key(owner.toUnsafe(), name, valueParameterCount), impl); + registerIntrinsic(owner.toUnsafe(), name, valueParameterCount, impl); } diff --git a/compiler/frontend/src/jet/Ranges.jet b/compiler/frontend/src/jet/Ranges.jet index ff24d077f30..ee0635bf3a4 100644 --- a/compiler/frontend/src/jet/Ranges.jet +++ b/compiler/frontend/src/jet/Ranges.jet @@ -18,6 +18,10 @@ public class IntRange(public val start : Int, public val size : Int) : Range, LongIterable { @@ -34,6 +38,10 @@ public class LongRange(public val start : Long, public val size : Long) : Range< public fun step(step: Long) : LongIterator public val isReversed : Boolean + + public class object { + public val EMPTY: LongRange + } } public class ByteRange(public val start : Byte, public val size : Int) : Range, ByteIterable { @@ -50,6 +58,10 @@ public class ByteRange(public val start : Byte, public val size : Int) : Range, ShortIterable { @@ -66,6 +78,10 @@ public class ShortRange(public val start : Short, public val size : Int) : Range public fun step(step: Int) : ShortIterator public val isReversed : Boolean + + public class object { + public val EMPTY: ShortRange + } } public class CharRange(public val start : Char, public val size : Int) : Range, CharIterable { @@ -82,6 +98,10 @@ public class CharRange(public val start : Char, public val size : Int) : Range { @@ -94,6 +114,10 @@ public class FloatRange(public val start : Float, public val size : Float) : Ran public fun step(step: Float) : FloatIterator public val isReversed : Boolean + + public class object { + public val EMPTY: FloatRange + } } public class DoubleRange(public val start : Double, public val size : Double) : Range { @@ -106,4 +130,8 @@ public class DoubleRange(public val start : Double, public val size : Double) : public fun step(step: Double) : DoubleIterator public val isReversed : Boolean + + public class object { + public val EMPTY: DoubleRange + } } diff --git a/compiler/testData/builtin-classes.txt b/compiler/testData/builtin-classes.txt index c9f6c70f358..eb9f63cc1b8 100644 --- a/compiler/testData/builtin-classes.txt +++ b/compiler/testData/builtin-classes.txt @@ -130,6 +130,10 @@ public final class jet.ByteRange : jet.Range, jet.ByteIterable { public final val size: jet.Int public final val start: jet.Byte public final fun step(/*0*/ step: jet.Int): jet.ByteIterator + public final class object jet.ByteRange. : jet.Any { + internal final /*constructor*/ fun (): jet.ByteRange. + public final val EMPTY: jet.ByteRange + } } public final class jet.Char : jet.Number, jet.Comparable { public final /*constructor*/ fun (): jet.Char @@ -220,6 +224,10 @@ public final class jet.CharRange : jet.Range, jet.CharIterable { public final val size: jet.Int public final val start: jet.Char public final fun step(/*0*/ step: jet.Int): jet.CharIterator + public final class object jet.CharRange. : jet.Any { + internal final /*constructor*/ fun (): jet.CharRange. + public final val EMPTY: jet.CharRange + } } public abstract trait jet.CharSequence : jet.Any { public abstract fun get(/*0*/ index: jet.Int): jet.Char @@ -319,6 +327,10 @@ public final class jet.DoubleRange : jet.Range { public final val size: jet.Double public final val start: jet.Double public final fun step(/*0*/ step: jet.Double): jet.DoubleIterator + public final class object jet.DoubleRange. : jet.Any { + internal final /*constructor*/ fun (): jet.DoubleRange. + public final val EMPTY: jet.DoubleRange + } } public abstract class jet.ExtensionFunction0 : jet.Any { public final /*constructor*/ fun (): jet.ExtensionFunction0 @@ -503,6 +515,10 @@ public final class jet.FloatRange : jet.Range { public final val size: jet.Float public final val start: jet.Float public final fun step(/*0*/ step: jet.Float): jet.FloatIterator + public final class object jet.FloatRange. : jet.Any { + internal final /*constructor*/ fun (): jet.FloatRange. + public final val EMPTY: jet.FloatRange + } } public abstract class jet.Function0 : jet.Any { public final /*constructor*/ fun (): jet.Function0 @@ -700,6 +716,10 @@ public final class jet.IntRange : jet.Range, jet.IntIterable { public final val size: jet.Int public final val start: jet.Int public final fun step(/*0*/ step: jet.Int): jet.IntIterator + public final class object jet.IntRange. : jet.Any { + internal final /*constructor*/ fun (): jet.IntRange. + public final val EMPTY: jet.IntRange + } } public abstract trait jet.Iterable : jet.Any { public abstract fun iterator(): jet.Iterator @@ -808,6 +828,10 @@ public final class jet.LongRange : jet.Range, jet.LongIterable { public final val size: jet.Long public final val start: jet.Long public final fun step(/*0*/ step: jet.Long): jet.LongIterator + public final class object jet.LongRange. : jet.Any { + internal final /*constructor*/ fun (): jet.LongRange. + public final val EMPTY: jet.LongRange + } } public final class jet.Nothing { private final /*constructor*/ fun (): jet.Nothing @@ -920,6 +944,10 @@ public final class jet.ShortRange : jet.Range, jet.ShortIterable { public final val size: jet.Int public final val start: jet.Short public final fun step(/*0*/ step: jet.Int): jet.ShortIterator + public final class object jet.ShortRange. : jet.Any { + internal final /*constructor*/ fun (): jet.ShortRange. + public final val EMPTY: jet.ShortRange + } } public final class jet.String : jet.Comparable, jet.CharSequence { public final /*constructor*/ fun (): jet.String diff --git a/compiler/testData/codegen/emptyRanges.kt b/compiler/testData/codegen/emptyRanges.kt new file mode 100644 index 00000000000..ae1465da971 --- /dev/null +++ b/compiler/testData/codegen/emptyRanges.kt @@ -0,0 +1,24 @@ +fun box(): String { + if (IntRange(0, 0) != IntRange.EMPTY) { + return IntRange.EMPTY.toString() + } + if (CharRange(0.toChar(), 0) != CharRange.EMPTY) { + return CharRange.EMPTY.toString() + } + if (ByteRange(0, 0) != ByteRange.EMPTY) { + return ByteRange.EMPTY.toString() + } + if (ShortRange(0, 0) != ShortRange.EMPTY) { + return ShortRange.EMPTY.toString() + } + if (FloatRange(0.toFloat(), 0.toFloat()) != FloatRange.EMPTY) { + return FloatRange.EMPTY.toString() + } + if (LongRange(0, 0) != LongRange.EMPTY) { + return LongRange.EMPTY.toString() + } + if (DoubleRange(0.0, 0.0) != DoubleRange.EMPTY) { + return DoubleRange.EMPTY.toString() + } + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java b/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java index 573207df0b0..e27326900e4 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java @@ -444,4 +444,8 @@ public class PrimitiveTypesTest extends CodegenTestCase { public void testKt2275() { blackBoxFile("regressions/kt2275.kt"); } + + public void testEmptyRanges() throws Exception { + blackBoxFile("emptyRanges.kt"); + } }