From 555ebebe1b9f5d7ad194fd152f01836239e7b0bc Mon Sep 17 00:00:00 2001 From: svtk Date: Fri, 2 Sep 2011 18:18:16 +0400 Subject: [PATCH 01/19] added default property accessor descriptors --- .../jet/codegen/ExpressionCodegen.java | 6 +++-- .../PropertyAccessorDescriptor.java | 9 ++++++- .../descriptors/PropertyGetterDescriptor.java | 4 ++-- .../descriptors/PropertySetterDescriptor.java | 4 ++-- .../lang/resolve/ClassDescriptorResolver.java | 24 ++++++++++++++----- 5 files changed, 34 insertions(+), 13 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index f0609efca0f..2c956b120c1 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -784,8 +784,10 @@ public class ExpressionCodegen extends JetVisitor { setter = null; } else { - getter = isInsideClass && propertyDescriptor.getGetter() == null ? null : typeMapper.mapGetterSignature(propertyDescriptor); - setter = isInsideClass && propertyDescriptor.getSetter() == null ? null : typeMapper.mapSetterSignature(propertyDescriptor); + getter = isInsideClass && (propertyDescriptor.getGetter() == null || propertyDescriptor.getGetter().isDefault()) + ? null : typeMapper.mapGetterSignature(propertyDescriptor); + setter = isInsideClass && (propertyDescriptor.getSetter() == null || propertyDescriptor.getSetter().isDefault()) + ? null : typeMapper.mapSetterSignature(propertyDescriptor); } String owner; diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/PropertyAccessorDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/PropertyAccessorDescriptor.java index a24561ec27a..7192db55745 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/PropertyAccessorDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/PropertyAccessorDescriptor.java @@ -13,6 +13,7 @@ import java.util.List; public abstract class PropertyAccessorDescriptor extends DeclarationDescriptorImpl implements FunctionDescriptor, MemberDescriptor { private final boolean hasBody; + private final boolean isDefault; private final MemberModifiers modifiers; protected PropertyAccessorDescriptor( @@ -20,16 +21,22 @@ public abstract class PropertyAccessorDescriptor extends DeclarationDescriptorIm @NotNull PropertyDescriptor correspondingProperty, @NotNull List annotations, @NotNull String name, - boolean hasBody) { + boolean hasBody, + boolean isDefault) { super(correspondingProperty.getContainingDeclaration(), annotations, name); this.modifiers = modifiers; this.hasBody = hasBody; + this.isDefault = isDefault; } public boolean hasBody() { return hasBody; } + public boolean isDefault() { + return isDefault; + } + @NotNull @Override public PropertyAccessorDescriptor getOriginal() { diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java index e434436c598..110dc5cfd38 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java @@ -17,8 +17,8 @@ public class PropertyGetterDescriptor extends PropertyAccessorDescriptor { private final Set overriddenGetters = Sets.newHashSet(); private JetType returnType; - public PropertyGetterDescriptor(@NotNull MemberModifiers modifiers, @NotNull PropertyDescriptor correspondingProperty, @NotNull List annotations, @Nullable JetType returnType, boolean hasBody) { - super(modifiers, correspondingProperty, annotations, "get-" + correspondingProperty.getName(), hasBody); + public PropertyGetterDescriptor(@NotNull MemberModifiers modifiers, @NotNull PropertyDescriptor correspondingProperty, @NotNull List annotations, @Nullable JetType returnType, boolean hasBody, boolean isDefault) { + super(modifiers, correspondingProperty, annotations, "get-" + correspondingProperty.getName(), hasBody, isDefault); this.returnType = returnType == null ? correspondingProperty.getOutType() : returnType; } diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java index 2e31121f278..3c2a483a09b 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java @@ -18,8 +18,8 @@ public class PropertySetterDescriptor extends PropertyAccessorDescriptor { private MutableValueParameterDescriptor parameter; private final Set overriddenSetters = Sets.newHashSet(); - public PropertySetterDescriptor(@NotNull MemberModifiers modifiers, @NotNull PropertyDescriptor correspondingProperty, @NotNull List annotations, boolean hasBody) { - super(modifiers, correspondingProperty, annotations, "set-" + correspondingProperty.getName(), hasBody); + public PropertySetterDescriptor(@NotNull MemberModifiers modifiers, @NotNull PropertyDescriptor correspondingProperty, @NotNull List annotations, boolean hasBody, boolean isDefault) { + super(modifiers, correspondingProperty, annotations, "set-" + correspondingProperty.getName(), hasBody, isDefault); } public void initialize(@NotNull MutableValueParameterDescriptor parameter) { diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index 7a94482da7f..ebff18e8796 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -568,18 +568,20 @@ public class ClassDescriptorResolver { @Nullable private PropertySetterDescriptor resolvePropertySetterDescriptor(@NotNull JetScope scope, @NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) { JetPropertyAccessor setter = property.getSetter(); - if (setter != null && !property.isVar()) { - trace.getErrorHandler().genericError(setter.asElement().getNode(), "A 'val'-property cannot have a setter"); + if (! property.isVar()) { + if (setter != null) { + trace.getErrorHandler().genericError(setter.asElement().getNode(), "A 'val'-property cannot have a setter"); + } return null; } - PropertySetterDescriptor setterDescriptor = null; + PropertySetterDescriptor setterDescriptor; if (setter != null) { List annotations = annotationResolver.resolveAnnotations(scope, setter.getModifierList()); JetParameter parameter = setter.getParameter(); setterDescriptor = new PropertySetterDescriptor( resolveModifiers(setter.getModifierList(), DEFAULT_MODIFIERS), // TODO : default modifiers differ in different contexts - propertyDescriptor, annotations, setter.getBodyExpression() != null); + propertyDescriptor, annotations, setter.getBodyExpression() != null, false); if (parameter != null) { if (parameter.isRef()) { trace.getErrorHandler().genericError(parameter.getRefNode(), "Setter parameters can not be 'ref'"); @@ -614,12 +616,17 @@ public class ClassDescriptorResolver { } trace.record(BindingContext.PROPERTY_ACCESSOR, setter, setterDescriptor); } + else { + setterDescriptor = new PropertySetterDescriptor( + propertyDescriptor.getModifiers(), + propertyDescriptor, Collections.emptyList(), false, true); + } return setterDescriptor; } @Nullable private PropertyGetterDescriptor resolvePropertyGetterDescriptor(@NotNull JetScope scope, @NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) { - PropertyGetterDescriptor getterDescriptor = null; + PropertyGetterDescriptor getterDescriptor; JetPropertyAccessor getter = property.getGetter(); if (getter != null) { List annotations = annotationResolver.resolveAnnotations(scope, getter.getModifierList()); @@ -632,9 +639,14 @@ public class ClassDescriptorResolver { getterDescriptor = new PropertyGetterDescriptor( resolveModifiers(getter.getModifierList(), DEFAULT_MODIFIERS), // TODO : default modifiers differ in different contexts - propertyDescriptor, annotations, returnType, getter.getBodyExpression() != null); + propertyDescriptor, annotations, returnType, getter.getBodyExpression() != null, false); trace.record(BindingContext.PROPERTY_ACCESSOR, getter, getterDescriptor); } + else { + getterDescriptor = new PropertyGetterDescriptor( + propertyDescriptor.getModifiers(), + propertyDescriptor, Collections.emptyList(), propertyDescriptor.getOutType(), false, true); + } return getterDescriptor; } From 672756e45989eff2e510e0b2b7cd66cc249f4a09 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Sat, 3 Sep 2011 12:02:42 +0200 Subject: [PATCH 02/19] fix for KT-241 --- idea/src/jet/Library.jet | 2 +- .../jet/codegen/ExpressionCodegen.java | 90 +++++++++++++------ .../jet/codegen/FunctionCodegen.java | 2 +- .../lang/descriptors/PropertyDescriptor.java | 2 +- .../jetbrains/jet/lang/types/JetTypeImpl.java | 5 ++ .../jet/lang/types/JetTypeInferrer.java | 2 +- .../codegen/controlStructures/forUserType.jet | 45 ++++++++++ idea/testData/codegen/regressions/kt259.jet | 5 ++ .../jet/codegen/ControlStructuresTest.java | 4 + 9 files changed, 127 insertions(+), 30 deletions(-) create mode 100644 idea/testData/codegen/controlStructures/forUserType.jet diff --git a/idea/src/jet/Library.jet b/idea/src/jet/Library.jet index 211e49cf2db..0d535035baa 100644 --- a/idea/src/jet/Library.jet +++ b/idea/src/jet/Library.jet @@ -42,7 +42,7 @@ fun Any?.toString() : String// = this === other class Iterator { fun next() : T - abstract val hasNext : Boolean + abstract fun hasNext() : Boolean } class Iterable { diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 2c956b120c1..eb2bd96d784 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -11,11 +11,13 @@ import jet.Range; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethod; import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods; +import org.jetbrains.jet.lang.ErrorHandler; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; +import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor; import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeProjection; @@ -38,20 +40,13 @@ public class ExpressionCodegen extends JetVisitor { private static final String CLASS_STRING = "java/lang/String"; public static final String CLASS_STRING_BUILDER = "java/lang/StringBuilder"; private static final String CLASS_COMPARABLE = "java/lang/Comparable"; - private static final String CLASS_ITERABLE = "java/lang/Iterable"; - private static final String CLASS_ITERATOR = "java/util/Iterator"; private static final String CLASS_RANGE = "jet/Range"; private static final String CLASS_NO_PATTERN_MATCHED_EXCEPTION = "jet/NoPatternMatchedException"; private static final String CLASS_TYPE_CAST_EXCEPTION = "jet/TypeCastException"; - private static final String ITERABLE_ITERATOR_DESCRIPTOR = "()Ljava/util/Iterator;"; - private static final String ITERATOR_HASNEXT_DESCRIPTOR = "()Z"; - private static final String ITERATOR_NEXT_DESCRIPTOR = "()Ljava/lang/Object;"; - private static final Type OBJECT_TYPE = Type.getType(Object.class); private static final Type INTEGER_TYPE = Type.getType(Integer.class); - private static final Type ITERATOR_TYPE = Type.getType(Iterator.class); private static final Type THROWABLE_TYPE = Type.getType(Throwable.class); private static final Type STRING_TYPE = Type.getObjectType(CLASS_STRING); @@ -242,33 +237,43 @@ public class ExpressionCodegen extends JetVisitor { } else { final DeclarationDescriptor descriptor = expressionType.getConstructor().getDeclarationDescriptor(); - final PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor); - if (declaration instanceof PsiClass) { - final Project project = declaration.getProject(); - final PsiClass iterable = JavaPsiFacade.getInstance(project).findClass("java.lang.Iterable", ProjectScope.getAllScope(project)); - if (((PsiClass) declaration).isInheritor(iterable, true)) { - generateForInIterable(expression, loopRangeType); - return StackValue.none(); - } - } if (isClass(descriptor, "IntRange")) { // TODO IntRange subclasses new ForInRangeLoopGenerator(expression, loopRangeType).invoke(); return StackValue.none(); } - throw new UnsupportedOperationException("for/in loop currently only supported for arrays and Iterable instances"); + + generateForInIterable(expression, loopRangeType); + return StackValue.none(); } } private void generateForInIterable(JetForExpression expression, Type loopRangeType) { + final JetExpression loopRange = expression.getLoopRange(); + + FunctionDescriptor iteratorDescriptor = bindingContext.get(BindingContext.LOOP_RANGE_ITERATOR, loopRange); + FunctionDescriptor nextDescriptor = bindingContext.get(BindingContext.LOOP_RANGE_NEXT, loopRange); + DeclarationDescriptor hasNextDescriptor = bindingContext.get(BindingContext.LOOP_RANGE_HAS_NEXT, loopRange); + + if(iteratorDescriptor == null) + throw new IllegalStateException("No iterator() method " + ErrorHandler.atLocation(loopRange)); + if(nextDescriptor == null) + throw new IllegalStateException("No next() method " + ErrorHandler.atLocation(loopRange)); + if(hasNextDescriptor == null) + throw new IllegalStateException("No iterator() method " + ErrorHandler.atLocation(loopRange)); + final JetParameter loopParameter = expression.getLoopParameter(); final VariableDescriptor parameterDescriptor = bindingContext.get(BindingContext.VALUE_PARAMETER, loopParameter); + + JetType iteratorType = parameterDescriptor.getOutType(); + Type asmIterType = typeMapper.boxType(typeMapper.mapType(iteratorType)); + JetType paramType = parameterDescriptor.getOutType(); Type asmParamType = typeMapper.boxType(typeMapper.mapType(paramType)); int iteratorVar = myMap.enterTemp(); gen(expression.getLoopRange(), loopRangeType); - v.invokeinterface(CLASS_ITERABLE, "iterator", ITERABLE_ITERATOR_DESCRIPTOR); - v.store(iteratorVar, ITERATOR_TYPE); + invokeFunctionNoParams(iteratorDescriptor, asmIterType, v); + v.store(iteratorVar, asmIterType); Label begin = new Label(); Label end = new Label(); @@ -276,13 +281,21 @@ public class ExpressionCodegen extends JetVisitor { myBreakTargets.push(end); v.mark(begin); - v.load(iteratorVar, ITERATOR_TYPE); - v.invokeinterface(CLASS_ITERATOR, "hasNext", ITERATOR_HASNEXT_DESCRIPTOR); + v.load(iteratorVar, asmIterType); + FunctionDescriptor hND; + if(hasNextDescriptor instanceof FunctionDescriptor) { + hND = (FunctionDescriptor) hasNextDescriptor; + } + else { + hND = ((PropertyDescriptor) hasNextDescriptor).getGetter(); + } + invokeFunctionNoParams(hND, Type.BOOLEAN_TYPE, v); v.ifeq(end); myMap.enter(parameterDescriptor, asmParamType.getSize()); - v.load(iteratorVar, ITERATOR_TYPE); - v.invokeinterface(CLASS_ITERATOR, "next", ITERATOR_NEXT_DESCRIPTOR); + v.load(iteratorVar, asmIterType); + invokeFunctionNoParams(nextDescriptor, asmParamType, v); + // TODO checkcast should be generated via StackValue if (asmParamType.getSort() == Type.OBJECT && !"java.lang.Object".equals(asmParamType.getClassName())) { v.checkcast(asmParamType); @@ -770,11 +783,36 @@ public class ExpressionCodegen extends JetVisitor { return myMap.getIndex(descriptor); } + public void invokeFunctionNoParams(FunctionDescriptor functionDescriptor, Type type, InstructionAdapterEx v) { + DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration(); + boolean isStatic = containingDeclaration instanceof NamespaceDescriptorImpl; + functionDescriptor = functionDescriptor.getOriginal(); + String owner; + + boolean isInterface; + boolean isInsideClass = containingDeclaration == contextType(); + if (isInsideClass || isStatic) { + owner = typeMapper.getOwner(functionDescriptor, contextKind()); + isInterface = false; + } + else { + owner = typeMapper.getOwner(functionDescriptor, OwnerKind.INTERFACE); + if(containingDeclaration instanceof JavaClassDescriptor) { + PsiClass psiElement = (PsiClass) bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, containingDeclaration); + isInterface = psiElement.isInterface(); + } + else + isInterface = !(containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor) containingDeclaration).isObject()); + } + + v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : isInterface ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL, owner, functionDescriptor.getName(), typeMapper.mapSignature(functionDescriptor.getName(),functionDescriptor).getDescriptor()); + StackValue.onStack(typeMapper.mapType(functionDescriptor.getReturnType())).coerce(type, v); + } + public StackValue intermediateValueForProperty(PropertyDescriptor propertyDescriptor, final boolean forceField, boolean forceInterface) { DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); boolean isStatic = containingDeclaration instanceof NamespaceDescriptorImpl; - while(propertyDescriptor != propertyDescriptor.getOriginal()) - propertyDescriptor = propertyDescriptor.getOriginal(); + propertyDescriptor = propertyDescriptor.getOriginal(); final JetType outType = propertyDescriptor.getOutType(); boolean isInsideClass = !forceInterface && containingDeclaration == contextType(); Method getter; @@ -1779,7 +1817,7 @@ public class ExpressionCodegen extends JetVisitor { v.anew(JetTypeMapper.TYPE_TYPEINFO); v.dup(); v.aconst(jvmType); - v.aconst(jetType.isNullable()); + v.iconst(jetType.isNullable()?1:0); List arguments = jetType.getArguments(); if (arguments.size() > 0) { v.iconst(arguments.size()); diff --git a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 072be3d077a..51d53ad7b9c 100644 --- a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -133,7 +133,7 @@ public class FunctionCodegen { if(overriddenFunctions.size() > 0) { for (FunctionDescriptor overriddenFunction : overriddenFunctions) { // TODO should we check params here as well? - if(!JetTypeImpl.equalTypes(overriddenFunction.getReturnType(), functionDescriptor.getReturnType(), JetTypeImpl.EMPTY_AXIOMS)) { + if(!JetTypeImpl.equalTypeClasses(overriddenFunction.getReturnType(), functionDescriptor.getReturnType())) { generateBridgeMethod(jvmSignature, state.getTypeMapper().mapSignature(overriddenFunction.getName(), overriddenFunction)); } } diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java index 552f257ade8..de3545e086a 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java @@ -39,7 +39,7 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Member this.isVar = isVar; this.memberModifiers = memberModifiers; this.receiverType = receiverType; - this.original = original == null ? this : original; + this.original = original == null ? this : original.getOriginal(); } public PropertyDescriptor( diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeImpl.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeImpl.java index ac57307b37f..cbdc61d7e5f 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeImpl.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeImpl.java @@ -3,6 +3,7 @@ package org.jetbrains.jet.lang.types; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotatedImpl; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; @@ -114,6 +115,10 @@ public final class JetTypeImpl extends AnnotatedImpl implements JetType { } + public static boolean equalTypeClasses(@NotNull JetType type1, @NotNull JetType type2) { + return type1.getConstructor().getDeclarationDescriptor().getOriginal().equals(type2.getConstructor().getDeclarationDescriptor().getOriginal()); + } + public static boolean equalTypes(@NotNull JetType type1, @NotNull JetType type2, @NotNull BiMap equalityAxioms) { if (type1.isNullable() != type2.isNullable()) { return false; diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 7a0d440b7c8..f6cf4ec7815 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -2078,7 +2078,7 @@ public class JetTypeInferrer { boolean hasNextPropertySupported = hasNextProperty != null; if (hasNextFunctionSupported && hasNextPropertySupported && !ErrorUtils.isErrorType(iteratorType)) { // TODO : overload resolution rules impose priorities here??? - context.trace.getErrorHandler().genericError(reportErrorsOn, "An ambiguity between 'iterator().hasNext()' function and 'iterator().hasNext()' property"); + context.trace.getErrorHandler().genericError(reportErrorsOn, "An ambiguity between 'iterator().hasNext()' function and 'iterator().hasNext' property"); } else if (!hasNextFunctionSupported && !hasNextPropertySupported) { context.trace.getErrorHandler().genericError(reportErrorsOn, "Loop range must have an 'iterator().hasNext()' function or an 'iterator().hasNext' property"); diff --git a/idea/testData/codegen/controlStructures/forUserType.jet b/idea/testData/codegen/controlStructures/forUserType.jet new file mode 100644 index 00000000000..24425da2c4e --- /dev/null +++ b/idea/testData/codegen/controlStructures/forUserType.jet @@ -0,0 +1,45 @@ +fun box() : String { + val c5 = MyCollection3() + for (el in c5) {} + + val c1: java.lang.Iterable = MyCollection1() + for (el in c1) {} + + val c2 = MyCollection1() + for (el in c2) {} +/* + val c3: Iterable = MyCollection2() + for (el in c3) {} + + val c4 = MyCollection2() + for (el in c4) {} +*/ + return "OK" +} + +class MyCollection1(): java.lang.Iterable { + fun iterator(): java.util.Iterator = MyIterator() + + class MyIterator(): java.util.Iterator { + fun next() = 0 + fun hasNext() = false + } +} + +class MyCollection2(): Iterable { + fun iterator(): Iterator = MyIterator() + + class MyIterator(): Iterator { + fun next() = 0 + fun hasNext() = false + } +} + +class MyCollection3() { + fun iterator() = MyIterator() + + class MyIterator() { + fun next() = 0 + fun hasNext() = false + } +} diff --git a/idea/testData/codegen/regressions/kt259.jet b/idea/testData/codegen/regressions/kt259.jet index e4a1b9099d8..bf6ac4b0fe1 100644 --- a/idea/testData/codegen/regressions/kt259.jet +++ b/idea/testData/codegen/regressions/kt259.jet @@ -39,6 +39,11 @@ fun t3 () : Boolean { if(d.isT(10)) return false if(!d.isT(null)) return false + val f = B() + if(!f.isT("aaa")) return false + if(f.isT(10)) return false + if(!f.isT(null)) return false + val c = B() if(c.isT("aaa")) return false if(!c.isT(10)) return false diff --git a/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java b/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java index 3f154a44c31..0d703d1d242 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java @@ -140,4 +140,8 @@ public class ControlStructuresTest extends CodegenTestCase { assertTrue(caught); assertEquals("foobar", sb.toString()); } + + public void testForUserType() throws Exception { + blackBoxFile("controlStructures/forUserType.jet"); + } } From 44c4b2db3ddcb425bedc13dceb2768856582488e Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Sat, 3 Sep 2011 13:31:43 +0200 Subject: [PATCH 03/19] Iterable/Iterator in stdlib --- stdlib/src/jet/Iterable$$Impl.java | 4 ++++ stdlib/src/jet/Iterable.java | 5 +++++ stdlib/src/jet/Iterator$$Impl.java | 4 ++++ stdlib/src/jet/Iterator.java | 6 ++++++ 4 files changed, 19 insertions(+) create mode 100644 stdlib/src/jet/Iterable$$Impl.java create mode 100644 stdlib/src/jet/Iterable.java create mode 100644 stdlib/src/jet/Iterator$$Impl.java create mode 100644 stdlib/src/jet/Iterator.java diff --git a/stdlib/src/jet/Iterable$$Impl.java b/stdlib/src/jet/Iterable$$Impl.java new file mode 100644 index 00000000000..22a2b4ec40d --- /dev/null +++ b/stdlib/src/jet/Iterable$$Impl.java @@ -0,0 +1,4 @@ +package jet; + +public abstract class Iterable$$Impl implements Iterable { +} diff --git a/stdlib/src/jet/Iterable.java b/stdlib/src/jet/Iterable.java new file mode 100644 index 00000000000..b105b995d04 --- /dev/null +++ b/stdlib/src/jet/Iterable.java @@ -0,0 +1,5 @@ +package jet; + +public interface Iterable extends JetObject { + Iterator iterator (); +} diff --git a/stdlib/src/jet/Iterator$$Impl.java b/stdlib/src/jet/Iterator$$Impl.java new file mode 100644 index 00000000000..141ef338a48 --- /dev/null +++ b/stdlib/src/jet/Iterator$$Impl.java @@ -0,0 +1,4 @@ +package jet; + +public abstract class Iterator$$Impl implements Iterator { +} diff --git a/stdlib/src/jet/Iterator.java b/stdlib/src/jet/Iterator.java new file mode 100644 index 00000000000..001bdd83863 --- /dev/null +++ b/stdlib/src/jet/Iterator.java @@ -0,0 +1,6 @@ +package jet; + +public interface Iterator extends JetObject { + boolean hasNext(); + T next (); +} From c20a39dbd85fd1b9744a8db3fe2a300edc86c727 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Sat, 3 Sep 2011 13:39:28 +0200 Subject: [PATCH 04/19] more tests for for- --- .../jet/codegen/ExpressionCodegen.java | 2 +- .../codegen/controlStructures/forUserType.jet | 30 +++++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index eb2bd96d784..d3f56c7962a 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -268,7 +268,7 @@ public class ExpressionCodegen extends JetVisitor { Type asmIterType = typeMapper.boxType(typeMapper.mapType(iteratorType)); JetType paramType = parameterDescriptor.getOutType(); - Type asmParamType = typeMapper.boxType(typeMapper.mapType(paramType)); + Type asmParamType = typeMapper.mapType(paramType); int iteratorVar = myMap.enterTemp(); gen(expression.getLoopRange(), loopRangeType); diff --git a/idea/testData/codegen/controlStructures/forUserType.jet b/idea/testData/codegen/controlStructures/forUserType.jet index 24425da2c4e..cb070bb1c68 100644 --- a/idea/testData/codegen/controlStructures/forUserType.jet +++ b/idea/testData/codegen/controlStructures/forUserType.jet @@ -1,19 +1,26 @@ fun box() : String { + val c6 = MyCollection4() + for (el in c6) { + System.out?.println(el) + } + val c5 = MyCollection3() - for (el in c5) {} + for (el in c5) { + System.out?.println(el) + } val c1: java.lang.Iterable = MyCollection1() for (el in c1) {} val c2 = MyCollection1() for (el in c2) {} -/* + val c3: Iterable = MyCollection2() for (el in c3) {} val c4 = MyCollection2() for (el in c4) {} -*/ + return "OK" } @@ -39,7 +46,20 @@ class MyCollection3() { fun iterator() = MyIterator() class MyIterator() { - fun next() = 0 - fun hasNext() = false + var k : Int = 5 + + fun next() : Int? = k-- + fun hasNext() = k > 0 + } +} + +class MyCollection4() { + fun iterator() = MyIterator() + + class MyIterator() { + var k : Int = 5 + + fun next() : Int = k-- + fun hasNext() = k > 0 } } From 07b2ab347deca99d69d19d951b4beafc96bb311e Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Sat, 3 Sep 2011 17:09:49 +0200 Subject: [PATCH 05/19] more tests for for- --- .../jet/codegen/ExpressionCodegen.java | 13 ++-- .../jet/codegen/FunctionCodegen.java | 4 +- .../codegen/controlStructures/forUserType.jet | 69 ++++++++++++++++--- 3 files changed, 70 insertions(+), 16 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index d3f56c7962a..c75ea5a5549 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1,9 +1,7 @@ package org.jetbrains.jet.codegen; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.psi.search.ProjectScope; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import gnu.trove.THashSet; @@ -34,6 +32,7 @@ import java.util.*; /** * @author max * @author yole + * @author alex.tkachman */ public class ExpressionCodegen extends JetVisitor { private static final String CLASS_OBJECT = "java/lang/Object"; @@ -308,6 +307,7 @@ public class ExpressionCodegen extends JetVisitor { v.mark(end); int paramIndex = myMap.leave(parameterDescriptor); + //noinspection ConstantConditions v.visitLocalVariable(loopParameter.getName(), asmParamType.getDescriptor(), null, begin, end, paramIndex); myMap.leaveTemp(); myBreakTargets.pop(); @@ -363,6 +363,7 @@ public class ExpressionCodegen extends JetVisitor { cleanupTemp(); final int paramIndex = myMap.leave(parameterDescriptor); + //noinspection ConstantConditions v.visitLocalVariable(expression.getLoopParameter().getName(), asmParamType.getDescriptor(), null, condition, end, paramIndex); myBreakTargets.pop(); myContinueTargets.pop(); @@ -822,8 +823,10 @@ public class ExpressionCodegen extends JetVisitor { setter = null; } else { + //noinspection ConstantConditions getter = isInsideClass && (propertyDescriptor.getGetter() == null || propertyDescriptor.getGetter().isDefault()) ? null : typeMapper.mapGetterSignature(propertyDescriptor); + //noinspection ConstantConditions setter = isInsideClass && (propertyDescriptor.getSetter() == null || propertyDescriptor.getSetter().isDefault()) ? null : typeMapper.mapSetterSignature(propertyDescriptor); } @@ -1434,12 +1437,15 @@ public class ExpressionCodegen extends JetVisitor { value.dupReceiver(v, 0); value.put(asmType, v); if (asmType == Type.LONG_TYPE) { + //noinspection UnnecessaryBoxing v.aconst(Long.valueOf(increment)); } else if (asmType == Type.FLOAT_TYPE) { + //noinspection UnnecessaryBoxing v.aconst(Float.valueOf(increment)); } else if (asmType == Type.DOUBLE_TYPE) { + //noinspection UnnecessaryBoxing v.aconst(Double.valueOf(increment)); } else { @@ -1741,7 +1747,6 @@ public class ExpressionCodegen extends JetVisitor { v.mark(lblCheck); for (int i = 0; i < entries.size(); i++) { - final boolean isLast = i == entries.size() - 1; final StackValue tupleField = StackValue.field(OBJECT_TYPE, tupleClassName, "_" + (i + 1), false); final StackValue stackValue = generatePatternMatch(entries.get(i).getPattern(), false, tupleField, nextEntry); stackValue.condJump(lblPopAndFail, true, v); @@ -1956,7 +1961,7 @@ public class ExpressionCodegen extends JetVisitor { final String className = "jet/Tuple" + entries.size(); Type tupleType = Type.getObjectType(className); StringBuilder signature = new StringBuilder("("); - for (JetExpression entry : entries) { + for (int i = 0; i != entries.size(); ++i) { signature.append("Ljava/lang/Object;"); } signature.append(")V"); diff --git a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 51d53ad7b9c..f3e71709f1a 100644 --- a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -133,8 +133,8 @@ public class FunctionCodegen { if(overriddenFunctions.size() > 0) { for (FunctionDescriptor overriddenFunction : overriddenFunctions) { // TODO should we check params here as well? - if(!JetTypeImpl.equalTypeClasses(overriddenFunction.getReturnType(), functionDescriptor.getReturnType())) { - generateBridgeMethod(jvmSignature, state.getTypeMapper().mapSignature(overriddenFunction.getName(), overriddenFunction)); + if(!JetTypeImpl.equalTypeClasses(overriddenFunction.getOriginal().getReturnType(), functionDescriptor.getReturnType())) { + generateBridgeMethod(jvmSignature, state.getTypeMapper().mapSignature(overriddenFunction.getName(), overriddenFunction.getOriginal())); } } } diff --git a/idea/testData/codegen/controlStructures/forUserType.jet b/idea/testData/codegen/controlStructures/forUserType.jet index cb070bb1c68..be95e3b437e 100644 --- a/idea/testData/codegen/controlStructures/forUserType.jet +++ b/idea/testData/codegen/controlStructures/forUserType.jet @@ -1,25 +1,70 @@ fun box() : String { + var sum : Int = 0 + var i = 0 + val c6 = MyCollection4() + sum = 0 for (el in c6) { - System.out?.println(el) + sum = sum + el } + if(sum != 15) return "c6 failed" val c5 = MyCollection3() + sum = 0 for (el in c5) { - System.out?.println(el) + sum = sum + (el ?: 0) } + if(sum != 15) return "c5 failed" val c1: java.lang.Iterable = MyCollection1() - for (el in c1) {} + sum = 0 + for (el in c1) { + sum = sum + el + } + if(sum != 15) return "c1 failed" val c2 = MyCollection1() - for (el in c2) {} + sum = 0 + for (el in c2) { + sum = sum + el + } + if(sum != 15) return "c2 failed" val c3: Iterable = MyCollection2() - for (el in c3) {} + sum = 0 + for (el in c3) { + sum = sum + el + } + if(sum != 15) return "c3 failed" val c4 = MyCollection2() - for (el in c4) {} + sum = 0 + for (el in c4) { + sum = sum + el + } + if(sum != 15) return "c4 failed" + + val a : Array = Array (5) + for(el in 0..4) { + a[i] = i++ + } + sum = 0 + for (el in a) { + sum = sum + el + } + if(sum != 10) return "a failed" + + val b : Array = Array (5) + i = 0 + while(i < 5) { + b[i] = i++ + } + sum = 0 + for (el in b) { + sum = sum + (el ?: 0) + } + System.out?.println(sum) + if(sum != 10) return "b failed" return "OK" } @@ -28,8 +73,10 @@ class MyCollection1(): java.lang.Iterable { fun iterator(): java.util.Iterator = MyIterator() class MyIterator(): java.util.Iterator { - fun next() = 0 - fun hasNext() = false + var k : Int = 5 + + fun next() : Int = k-- + fun hasNext() = k > 0 } } @@ -37,8 +84,10 @@ class MyCollection2(): Iterable { fun iterator(): Iterator = MyIterator() class MyIterator(): Iterator { - fun next() = 0 - fun hasNext() = false + var k : Int = 5 + + fun next() : Int = k-- + fun hasNext() = k > 0 } } From 9ba167ee8dda8b52af699eab7194616b0c8124ea Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Sat, 3 Sep 2011 22:52:12 +0200 Subject: [PATCH 06/19] fix KT-249/KT-255 --- .../jet/codegen/ExpressionCodegen.java | 29 +++++++++------ .../codegen/ImplementationBodyCodegen.java | 17 +++++---- .../jet/lang/psi/JetObjectDeclaration.java | 2 +- idea/testData/codegen/regressions/kt249.jet | 35 +++++++++++++++++++ .../jetbrains/jet/codegen/ClassGenTest.java | 4 +++ 5 files changed, 67 insertions(+), 20 deletions(-) create mode 100644 idea/testData/codegen/regressions/kt249.jet diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index c75ea5a5549..8ac31b4188a 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -851,7 +851,7 @@ public class ExpressionCodegen extends JetVisitor { DeclarationDescriptor funDescriptor = resolveCalleeDescriptor(expression); if (funDescriptor instanceof ConstructorDescriptor) { - return generateConstructorCall(expression, (JetSimpleNameExpression) callee); + return generateConstructorCall(expression, (JetSimpleNameExpression) callee, receiver); } else if (funDescriptor instanceof FunctionDescriptor) { final FunctionDescriptor fd = (FunctionDescriptor) funDescriptor; @@ -1471,7 +1471,7 @@ public class ExpressionCodegen extends JetVisitor { return StackValue.none(); } - private StackValue generateConstructorCall(JetCallExpression expression, JetSimpleNameExpression constructorReference) { + private StackValue generateConstructorCall(JetCallExpression expression, JetSimpleNameExpression constructorReference, StackValue receiver) { DeclarationDescriptor constructorDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, constructorReference); final PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, constructorDescriptor); Type type; @@ -1486,11 +1486,26 @@ public class ExpressionCodegen extends JetVisitor { else { ClassDescriptor classDecl = (ClassDescriptor) constructorDescriptor.getContainingDeclaration(); + receiver.put(receiver.type, v); v.anew(type); - v.dup(); // TODO typechecker must verify that we're the outer class of the instance being created - pushOuterClassArguments(classDecl); + if (classDecl.getContainingDeclaration() instanceof ClassDescriptor) { + if(!receiver.type.equals(Type.VOID_TYPE)) { + // class object is in receiver + v.dupX1(); + v.swap(); + } + else { + // this$0 need to be put on stack + v.dup(); + v.load(0, JetTypeMapper.jetImplementationType(classDecl)); + } + } + else { + // regular case + v.dup(); + } CallableMethod method = typeMapper.mapToCallableMethod((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION); invokeMethodWithArguments(method, expression); @@ -1513,12 +1528,6 @@ public class ExpressionCodegen extends JetVisitor { generateTypeInfo(typeArgument); } - private void pushOuterClassArguments(ClassDescriptor classDecl) { - if (classDecl.getContainingDeclaration() instanceof ClassDescriptor) { - v.load(0, JetTypeMapper.jetImplementationType(classDecl)); - } - } - private Type generateJavaConstructorCall(JetCallExpression expression, PsiMethod constructor) { PsiClass javaClass = constructor.getContainingClass(); Type type = JetTypeMapper.psiClassType(javaClass); diff --git a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index e97de80ecdc..03e309abad5 100644 --- a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -147,7 +147,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } protected void generatePrimaryConstructor() { - ConstructorDescriptor constructorDescriptor = state.getBindingContext().get(BindingContext.CONSTRUCTOR, (JetElement) myClass); + ConstructorDescriptor constructorDescriptor = state.getBindingContext().get(BindingContext.CONSTRUCTOR, myClass); if (constructorDescriptor == null && !(myClass instanceof JetObjectDeclaration) && !isEnum(myClass)) return; Method method; @@ -193,10 +193,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.invokespecial(superClass, "", /* TODO super constructor descriptor */"()V"); } - final DeclarationDescriptor outerDescriptor = getOuterClassDescriptor(); - if (outerDescriptor instanceof ClassDescriptor) { - final ClassDescriptor outerClassDescriptor = (ClassDescriptor) outerDescriptor; - final Type type = JetTypeMapper.jetImplementationType(outerClassDescriptor); + final ClassDescriptor outerDescriptor = getOuterClassDescriptor(); + if (outerDescriptor != null && !outerDescriptor.isObject()) { + final Type type = JetTypeMapper.jetImplementationType(outerDescriptor); String interfaceDesc = type.getDescriptor(); final String fieldName = "this$0"; v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, fieldName, interfaceDesc, null, null); @@ -216,7 +215,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { HashSet overridden = new HashSet(); for (JetDeclaration declaration : myClass.getDeclarations()) { if (declaration instanceof JetFunction) { - overridden.addAll(state.getBindingContext().get(BindingContext.FUNCTION, (JetNamedFunction) declaration).getOverriddenFunctions()); + overridden.addAll(state.getBindingContext().get(BindingContext.FUNCTION, declaration).getOverriddenFunctions()); } } @@ -410,8 +409,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { protected void generateInitializers(ExpressionCodegen codegen, InstructionAdapter iv) { for (JetDeclaration declaration : myClass.getDeclarations()) { if (declaration instanceof JetProperty) { - final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, (JetProperty) declaration); - if ((boolean) state.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) { + final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, declaration); + if (state.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) { final JetExpression initializer = ((JetProperty) declaration).getInitializer(); if (initializer != null) { iv.load(0, JetTypeMapper.TYPE_OBJECT); @@ -436,7 +435,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { propertyCodegen.gen((JetProperty) declaration); } else if (declaration instanceof JetFunction) { - if (!overriden.contains(state.getBindingContext().get(BindingContext.FUNCTION, (JetNamedFunction) declaration))) { + if (!overriden.contains(state.getBindingContext().get(BindingContext.FUNCTION, declaration))) { functionCodegen.gen((JetNamedFunction) declaration); } } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetObjectDeclaration.java b/idea/src/org/jetbrains/jet/lang/psi/JetObjectDeclaration.java index dc3c76bc5f9..fae5958f7d2 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetObjectDeclaration.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetObjectDeclaration.java @@ -22,7 +22,7 @@ public class JetObjectDeclaration extends JetNamedDeclaration implements JetClas @Override public String getName() { JetObjectDeclarationName nameAsDeclaration = getNameAsDeclaration(); - return nameAsDeclaration == null ? "" : nameAsDeclaration.getName(); + return nameAsDeclaration == null ? "ClassObj" : nameAsDeclaration.getName(); } @Override diff --git a/idea/testData/codegen/regressions/kt249.jet b/idea/testData/codegen/regressions/kt249.jet new file mode 100644 index 00000000000..d4f61650fd6 --- /dev/null +++ b/idea/testData/codegen/regressions/kt249.jet @@ -0,0 +1,35 @@ +namespace x + +class Outer(val name: String) { + class Inner() { + val me = name + + class object { + fun bar() = "bar" + } + } + + class object { + class StaticInner() { + class object { + fun f() = "oo" + } + } + } +} + +fun box (): String { + val inner = Outer("mama").Inner() //verify error + if(inner.me != "mama") + return "fail" + + val outer = Outer ("papa") + val inner2 = outer.Inner () + if(inner2.me != "papa") + return "fail" + + if(Outer.StaticInner.f() != "oo" ) + return "fail" + + return "OK" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java index 2a9fd6c98e7..8a17b3d4887 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -168,4 +168,8 @@ public class ClassGenTest extends CodegenTestCase { final Method rgbMethod = colorClass.getMethod("getRgb"); assertEquals(0xFF0000, rgbMethod.invoke(redValue)); } + + public void testKt249() throws Exception { + blackBoxFile("regressions/kt249.jet"); + } } From e862e8471aa8d2d8bb7f50d281a3832d8eb15e73 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Sun, 4 Sep 2011 08:55:06 +0200 Subject: [PATCH 07/19] micro code cleaning --- .../jetbrains/jet/codegen/ClassCodegen.java | 2 +- .../jet/codegen/ExpressionCodegen.java | 26 +++++++++---------- .../codegen/ImplementationBodyCodegen.java | 2 +- .../jet/codegen/intrinsics/Increment.java | 6 ++--- .../jetbrains/jet/codegen/intrinsics/Inv.java | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java index c7d6d88809f..97f0cd3dda7 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java @@ -59,7 +59,7 @@ public class ClassCodegen { v.anew(JetTypeMapper.TYPE_TYPEINFO); v.dup(); v.aconst(asmType); - v.aconst(isNullable); + v.iconst(isNullable?1:0); v.invokespecial("jet/typeinfo/TypeInfo", "", "(Ljava/lang/Class;Z)V"); } } diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 8ac31b4188a..a05c53a0fc8 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -395,7 +395,7 @@ public class ExpressionCodegen extends JetVisitor { v.arraylength(); v.store(myLengthVar, Type.INT_TYPE); myIndexVar = myMap.enterTemp(); - v.aconst(0); + v.iconst(0); v.store(myIndexVar, Type.INT_TYPE); } @@ -1178,7 +1178,7 @@ public class ExpressionCodegen extends JetVisitor { Label end = new Label(); v.goTo(end); v.mark(ifFalse); - v.aconst(false); + v.iconst(0); v.mark(end); return StackValue.onStack(Type.BOOLEAN_TYPE); } @@ -1191,7 +1191,7 @@ public class ExpressionCodegen extends JetVisitor { Label end = new Label(); v.goTo(end); v.mark(ifTrue); - v.aconst(true); + v.iconst(1); v.mark(end); return StackValue.onStack(Type.BOOLEAN_TYPE); } @@ -1243,11 +1243,11 @@ public class ExpressionCodegen extends JetVisitor { v.ifnull(bothNull); v.mark(leftNull); v.pop2(); - v.aconst(Boolean.FALSE); + v.iconst(0); v.goTo(end); v.mark(bothNull); v.pop2(); - v.aconst(Boolean.TRUE); + v.iconst(1); v.mark(end); final StackValue onStack = StackValue.onStack(Type.BOOLEAN_TYPE); @@ -1305,7 +1305,7 @@ public class ExpressionCodegen extends JetVisitor { private StackValue compareExpressionsOnStack(IElementType opToken, Type operandType) { if (operandType.getSort() == Type.OBJECT) { v.invokeinterface(CLASS_COMPARABLE, "compareTo", "(Ljava/lang/Object;)I"); - v.aconst(0); + v.iconst(0); operandType = Type.INT_TYPE; } return StackValue.cmp(opToken, operandType); @@ -1438,18 +1438,18 @@ public class ExpressionCodegen extends JetVisitor { value.put(asmType, v); if (asmType == Type.LONG_TYPE) { //noinspection UnnecessaryBoxing - v.aconst(Long.valueOf(increment)); + v.lconst(increment); } else if (asmType == Type.FLOAT_TYPE) { //noinspection UnnecessaryBoxing - v.aconst(Float.valueOf(increment)); + v.fconst(increment); } else if (asmType == Type.DOUBLE_TYPE) { //noinspection UnnecessaryBoxing - v.aconst(Double.valueOf(increment)); + v.dconst(increment); } else { - v.aconst(increment); + v.iconst(increment); } v.add(asmType); value.store(v); @@ -1766,7 +1766,7 @@ public class ExpressionCodegen extends JetVisitor { v.goTo(nextEntry); } else { - v.aconst(!negated); + v.iconst(!negated?1:0); } v.goTo(lblDone); v.mark(lblFail); @@ -1774,7 +1774,7 @@ public class ExpressionCodegen extends JetVisitor { v.goTo(nextEntry); } else { - v.aconst(negated); + v.iconst(negated?1:0); } v.mark(lblDone); return StackValue.onStack(Type.BOOLEAN_TYPE); @@ -1806,7 +1806,7 @@ public class ExpressionCodegen extends JetVisitor { v.goTo(end); v.mark(nope); v.pop(); - v.aconst(1); + v.iconst(1); v.mark(end); } else { diff --git a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 03e309abad5..7ce0246dccd 100644 --- a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -392,7 +392,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.dup(); iv.aconst(state.getTypeMapper().jvmType(descriptor, OwnerKind.INTERFACE)); - iv.aconst(false); + iv.iconst(0); iv.iconst(typeParamCount); iv.newarray(JetTypeMapper.TYPE_TYPEINFO); diff --git a/idea/src/org/jetbrains/jet/codegen/intrinsics/Increment.java b/idea/src/org/jetbrains/jet/codegen/intrinsics/Increment.java index 29c31db7899..dfb68c2fd42 100644 --- a/idea/src/org/jetbrains/jet/codegen/intrinsics/Increment.java +++ b/idea/src/org/jetbrains/jet/codegen/intrinsics/Increment.java @@ -35,13 +35,13 @@ public class Increment implements IntrinsicMethod { value.dupReceiver(v, 0); value.put(expectedType, v); if (expectedType == Type.LONG_TYPE) { - v.aconst(Long.valueOf(myDelta)); + v.lconst(myDelta); } else if (expectedType == Type.FLOAT_TYPE) { - v.aconst(Float.valueOf(myDelta)); + v.fconst(myDelta); } else if (expectedType == Type.DOUBLE_TYPE) { - v.aconst(Double.valueOf(myDelta)); + v.dconst(myDelta); } else { v.aconst(myDelta); diff --git a/idea/src/org/jetbrains/jet/codegen/intrinsics/Inv.java b/idea/src/org/jetbrains/jet/codegen/intrinsics/Inv.java index 263f480f8ee..fd6a663f964 100644 --- a/idea/src/org/jetbrains/jet/codegen/intrinsics/Inv.java +++ b/idea/src/org/jetbrains/jet/codegen/intrinsics/Inv.java @@ -16,7 +16,7 @@ public class Inv implements IntrinsicMethod { @Override public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { receiver.put(expectedType, v); - v.aconst(-1); + v.iconst(-1); v.xor(expectedType); return StackValue.onStack(expectedType); } From 22e2caf7f8e0ae33a6d5b5cafe8e221d48b31447 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Sun, 4 Sep 2011 14:20:40 +0200 Subject: [PATCH 08/19] fix for KT-237 --- .../jet/codegen/ExpressionCodegen.java | 9 +++++--- .../jet/codegen/FunctionCodegen.java | 2 ++ .../org/jetbrains/jet/codegen/StackValue.java | 23 +++++++++++++++++-- .../jet/lang/types/JetTypeInferrer.java | 4 ++-- idea/testData/codegen/regressions/kt237.jet | 20 ++++++++++++++++ .../jet/codegen/ControlStructuresTest.java | 4 ++++ .../jet/codegen/NamespaceGenTest.java | 6 +++++ .../jet/codegen/PatternMatchingTest.java | 10 ++++++-- 8 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 idea/testData/codegen/regressions/kt237.jet diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index a05c53a0fc8..df3972e60d0 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1112,11 +1112,14 @@ public class ExpressionCodegen extends JetVisitor { @Override public StackValue visitPredicateExpression(JetPredicateExpression expression, StackValue receiver) { - genToJVMStack(expression.getReceiverExpression()); + JetExpression expr = expression.getReceiverExpression(); + StackValue value = gen(expr); + Type receiverType = expressionType(expr); + value.put(receiverType, v); Label ifFalse = new Label(); Label end = new Label(); v.dup(); - StackValue result = gen(expression.getSelectorExpression()); + StackValue result = genQualified(StackValue.onStack(receiverType), expression.getSelectorExpression()); result.condJump(ifFalse, true, v); v.goTo(end); v.mark(ifFalse); @@ -1939,7 +1942,7 @@ public class ExpressionCodegen extends JetVisitor { if (!(declarationDescriptor instanceof FunctionDescriptor)) { throw new UnsupportedOperationException("expected function descriptor in when condition with call, found " + declarationDescriptor); } - conditionValue = invokeFunction((JetCallExpression) call, declarationDescriptor, StackValue.none()); + conditionValue = invokeFunction((JetCallExpression) call, declarationDescriptor, StackValue.onStack(subjectType)); } else if (call instanceof JetSimpleNameExpression) { final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) call); diff --git a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java index f3e71709f1a..484611fde09 100644 --- a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -66,6 +66,8 @@ public class FunctionCodegen { iv.invokevirtual(state.getTypeMapper().jvmName((ClassDescriptor) owner.getContextDescriptor(), OwnerKind.IMPLEMENTATION), function.getName(), function.getDescriptor()); if(JetTypeMapper.isPrimitive(function.getReturnType()) && !JetTypeMapper.isPrimitive(overriden.getReturnType())) iv.valueOf(function.getReturnType()); + if(function.getReturnType() == Type.VOID_TYPE) + iv.aconst(null); iv.areturn(overriden.getReturnType()); mv.visitMaxs(0, 0); mv.visitEnd(); diff --git a/idea/src/org/jetbrains/jet/codegen/StackValue.java b/idea/src/org/jetbrains/jet/codegen/StackValue.java index 17248b5c6f0..396ff664e85 100644 --- a/idea/src/org/jetbrains/jet/codegen/StackValue.java +++ b/idea/src/org/jetbrains/jet/codegen/StackValue.java @@ -156,8 +156,26 @@ public abstract class StackValue { protected void coerce(Type type, InstructionAdapter v) { if (type.equals(this.type)) return; - if (type.getSort() == Type.OBJECT && this.type.getSort() == Type.OBJECT) { - // v.checkcast(type); + if (type.getSort() == Type.VOID && this.type.getSort() != Type.VOID) { + if(this.type.getSize() == 1) + v.pop(); + else + v.pop2(); + } + else if (type.getSort() != Type.VOID && this.type.getSort() == Type.VOID) { + if(type.getSort() == Type.OBJECT) + v.aconst(null); + else if(type == Type.LONG_TYPE) + v.lconst(0); + else if(type == Type.FLOAT_TYPE) + v.fconst(0); + else if(type == Type.DOUBLE_TYPE) + v.dconst(0); + else + v.iconst(0); + } + else if (type.getSort() == Type.OBJECT && this.type.getSort() == Type.OBJECT) { + // v.checkcast(type); } else if (type.getSort() == Type.OBJECT) { box(this.type, type, v); @@ -201,6 +219,7 @@ public abstract class StackValue { @Override public void put(Type type, InstructionAdapter v) { + coerce(type, v); } } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index f6cf4ec7815..0e637764a7b 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -336,7 +336,7 @@ public class JetTypeInferrer { case SINGLE_FUNCTION_ARGUMENT_MISMATCH: if (argumentList != null) { // TODO : More helpful message. NOTE: there's a separate handling for this for constructors - trace.getErrorHandler().genericError(argumentList.getNode(), "Arguments do not match " + DescriptorRenderer.TEXT.render(resolutionResult.getFunctionDescriptor())); + trace.getErrorHandler().genericError(argumentList.getNode(), "Arguments do not match " + DescriptorRenderer.TEXT.render(resolutionResult.getFunctionDescriptor()) + " " + ErrorHandler.atLocation(referenceExpression)); } else { trace.getErrorHandler().unresolvedReference(referenceExpression); @@ -1188,7 +1188,7 @@ public class JetTypeInferrer { type = context.typeResolver.resolveType(context.scope, typeReference); } else { - context.trace.getErrorHandler().genericError(parameter.getNode(), "Type inference for parameters is not implemented yet"); + context.trace.getErrorHandler().genericError(parameter.getNode(), "Type inference for parameters is not implemented yet " + ErrorHandler.atLocation(parameter.getNavigationElement())); type = ErrorUtils.createErrorType("Not inferred"); } ValueParameterDescriptor valueParameterDescriptor = context.classDescriptorResolver.resolveValueParameterDescriptor(functionDescriptor, parameter, i, type); diff --git a/idea/testData/codegen/regressions/kt237.jet b/idea/testData/codegen/regressions/kt237.jet new file mode 100644 index 00000000000..1c19cf08e45 --- /dev/null +++ b/idea/testData/codegen/regressions/kt237.jet @@ -0,0 +1,20 @@ +fun foreach(array: Array, action: fun(Int): Unit) { + for (el in array) { + action(el) //exception through compilation (see below) + } +} +/* +fun almostFilter(array: Array, action: fun(Int): Int) { + for (el in array) { + action(el) + } +} +*/ +fun box() : String { + val a = Array (3) + a[0] = 0 + a[1] = 1 + a[2] = 2 + foreach(a, { (el : Int) : Unit => System.out?.println(el) }) + return "OK" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java b/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java index 0d703d1d242..8dff8181502 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java @@ -144,4 +144,8 @@ public class ControlStructuresTest extends CodegenTestCase { public void testForUserType() throws Exception { blackBoxFile("controlStructures/forUserType.jet"); } + + public void testKt237() throws Exception { + blackBoxFile("regressions/kt237.jet"); + } } diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index 30a934920b6..341818a2fb7 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -448,8 +448,14 @@ public class NamespaceGenTest extends CodegenTestCase { public void testPredicateOperator() throws Exception { loadText("fun foo(s: String) = s?startsWith(\"J\")"); final Method main = generateFunction(); + try { assertEquals("JetBrains", main.invoke(null, "JetBrains")); assertNull(main.invoke(null, "IntelliJ")); + } + catch (Throwable t) { + System.out.println(generateToText()); + t.printStackTrace(); + } } public void testEscapeSequence() throws Exception { diff --git a/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java b/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java index 1e5ac174c0d..98a29598db0 100644 --- a/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java @@ -80,8 +80,14 @@ public class PatternMatchingTest extends CodegenTestCase { public void testCall() throws Exception { loadText("fun foo(s: String) = when(s) { .startsWith(\"J\") => \"JetBrains\"; else => \"something\" }"); Method foo = generateFunction(); - assertEquals("JetBrains", foo.invoke(null, "Java")); - assertEquals("something", foo.invoke(null, "C#")); + try { + assertEquals("JetBrains", foo.invoke(null, "Java")); + assertEquals("something", foo.invoke(null, "C#")); + } + catch (Throwable t) { + System.out.println(generateToText()); + t.printStackTrace(); + } } public void testCallProperty() throws Exception { From 58765f2364748ca1704be434ed1255381e1695d4 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Sun, 4 Sep 2011 16:27:54 +0200 Subject: [PATCH 09/19] fix for KT-237. Unit as value part --- .../jet/codegen/ExpressionCodegen.java | 5 ++++ .../jetbrains/jet/codegen/JetTypeMapper.java | 20 +++++++++----- .../org/jetbrains/jet/codegen/StackValue.java | 2 +- idea/testData/codegen/regressions/kt237.jet | 27 ++++++++++++++++--- stdlib/src/jet/Tuple0.java | 26 ++++++++++++++++++ 5 files changed, 70 insertions(+), 10 deletions(-) create mode 100644 stdlib/src/jet/Tuple0.java diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index df3972e60d0..b3b00f2016a 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1970,6 +1970,11 @@ public class ExpressionCodegen extends JetVisitor { if (entries.size() > 22) { throw new UnsupportedOperationException("tuple too large"); } + if(entries.size() == 0) { + v.visitFieldInsn(Opcodes.GETSTATIC, "jet/Tuple0", "INSTANCE", "Ljet/Tuple0;"); + return StackValue.onStack(Type.getObjectType("jet/Tuple0")); + } + final String className = "jet/Tuple" + entries.size(); Type tupleType = Type.getObjectType(className); StringBuilder signature = new StringBuilder("("); diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 5713d75b728..df0860a370c 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -273,14 +273,22 @@ public class JetTypeMapper { return owner; } + public Type mapReturnType(@NotNull final JetType jetType, OwnerKind kind) { + if (jetType.equals(JetStandardClasses.getUnitType()) || jetType.equals(JetStandardClasses.getNothingType())) { + return Type.VOID_TYPE; + } + return mapType(jetType, kind); + } + + public Type mapReturnType(final JetType jetType) { + return mapReturnType(jetType, OwnerKind.INTERFACE); + } + public Type mapType(final JetType jetType) { return mapType(jetType, OwnerKind.INTERFACE); } public Type mapType(@NotNull final JetType jetType, OwnerKind kind) { - if (jetType.equals(JetStandardClasses.getUnitType()) || jetType.equals(JetStandardClasses.getNothingType())) { - return Type.VOID_TYPE; - } if (jetType.equals(standardLibrary.getIntType())) { return Type.INT_TYPE; } @@ -410,10 +418,10 @@ public class JetTypeMapper { if (returnTypeRef == null) { final FunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, f); final JetType type = functionDescriptor.getReturnType(); - returnType = mapType(type); + returnType = mapReturnType(type); } else { - returnType = mapType(bindingContext.get(BindingContext.TYPE, returnTypeRef)); + returnType = mapReturnType(bindingContext.get(BindingContext.TYPE, returnTypeRef)); } return new Method(f.getName(), returnType, parameterTypes.toArray(new Type[parameterTypes.size()])); } @@ -470,7 +478,7 @@ public class JetTypeMapper { for (ValueParameterDescriptor parameter : parameters) { parameterTypes.add(mapType(parameter.getOutType())); } - Type returnType = mapType(f.getReturnType()); + Type returnType = mapReturnType(f.getReturnType()); return new Method(name, returnType, parameterTypes.toArray(new Type[parameterTypes.size()])); } diff --git a/idea/src/org/jetbrains/jet/codegen/StackValue.java b/idea/src/org/jetbrains/jet/codegen/StackValue.java index 396ff664e85..800bb5be3b7 100644 --- a/idea/src/org/jetbrains/jet/codegen/StackValue.java +++ b/idea/src/org/jetbrains/jet/codegen/StackValue.java @@ -164,7 +164,7 @@ public abstract class StackValue { } else if (type.getSort() != Type.VOID && this.type.getSort() == Type.VOID) { if(type.getSort() == Type.OBJECT) - v.aconst(null); + v.visitFieldInsn(Opcodes.GETSTATIC, "jet/Tuple0", "INSTANCE", "Ljet/Tuple0;"); else if(type == Type.LONG_TYPE) v.lconst(0); else if(type == Type.FLOAT_TYPE) diff --git a/idea/testData/codegen/regressions/kt237.jet b/idea/testData/codegen/regressions/kt237.jet index 1c19cf08e45..adc16c93b60 100644 --- a/idea/testData/codegen/regressions/kt237.jet +++ b/idea/testData/codegen/regressions/kt237.jet @@ -1,20 +1,41 @@ -fun foreach(array: Array, action: fun(Int): Unit) { +fun main(args: Array?) { + val y: Unit = () //do not compile + A() //do not compile + C(()) //do not compile + //do not compile + System.out?.println(fff(())) //do not compile + System.out?.println(id(y)) //do not compile + System.out?.println(fff(id(y)) == id(foreach(Array(0),{(e : Int) : Unit => }))) //do not compile +} +class A() + +class C(val value: T) { + fun foo(): T = value +} + +fun fff(x: T) : T { return x } + +fun id(value: T): T = value + +fun foreach(array: Array?, action: fun(Int): Unit) { for (el in array) { action(el) //exception through compilation (see below) } } -/* + fun almostFilter(array: Array, action: fun(Int): Int) { for (el in array) { action(el) } } -*/ + fun box() : String { val a = Array (3) a[0] = 0 a[1] = 1 a[2] = 2 foreach(a, { (el : Int) : Unit => System.out?.println(el) }) + almostFilter(a, { (el : Int) : Int => el }) + main(null) return "OK" } \ No newline at end of file diff --git a/stdlib/src/jet/Tuple0.java b/stdlib/src/jet/Tuple0.java new file mode 100644 index 00000000000..8d9db829584 --- /dev/null +++ b/stdlib/src/jet/Tuple0.java @@ -0,0 +1,26 @@ +package jet; + +/** + * @author alex.tkachman + */ +public class Tuple0 { + public static final Tuple0 INSTANCE = new Tuple0(); + + private Tuple0() { + } + + @Override + public String toString() { + return "()"; + } + + @Override + public boolean equals(Object o) { + return o == INSTANCE; + } + + @Override + public int hashCode() { + return 239; + } +} \ No newline at end of file From 22b6f2864e988b1e8a7fe21da70c8ef5e50acf16 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Sun, 4 Sep 2011 18:09:53 +0200 Subject: [PATCH 10/19] fix for KT-152 --- .../jet/codegen/ExpressionCodegen.java | 30 +++++++++++++++++++ .../jetbrains/jet/codegen/JetTypeMapper.java | 4 +++ .../org/jetbrains/jet/codegen/StackValue.java | 2 +- .../jet/codegen/ControlStructuresTest.java | 10 +++++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index b3b00f2016a..241b8abb1f7 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1202,6 +1202,14 @@ public class ExpressionCodegen extends JetVisitor { private StackValue generateEquals(JetExpression left, JetExpression right, IElementType opToken) { Type leftType = expressionType(left); Type rightType = expressionType(right); + if(leftType == JetTypeMapper.TYPE_NOTHING) { + return genCmpWithNull(right, rightType, opToken); + } + + if(rightType == JetTypeMapper.TYPE_NOTHING) { + return genCmpWithNull(left, leftType, opToken); + } + if(JetTypeMapper.isPrimitive(leftType) != JetTypeMapper.isPrimitive(rightType)) { gen(left, leftType); v.valueOf(leftType); @@ -1217,6 +1225,28 @@ public class ExpressionCodegen extends JetVisitor { return generateEqualsForExpressionsOnStack(opToken, leftType, rightType); } + private StackValue genCmpWithNull(JetExpression exp, Type expType, IElementType opToken) { + gen(exp, typeMapper.boxType(expType)); + Label fail = new Label(), end = new Label(); + if(JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) { + v.ifnonnull(fail); + v.iconst(1); + v.goTo(end); + v.mark(fail); + v.iconst(0); + v.mark(end); + } + else { + v.ifnull(fail); + v.iconst(1); + v.goTo(end); + v.mark(fail); + v.iconst(0); + v.mark(end); + } + return StackValue.onStack(Type.BOOLEAN_TYPE); + } + private StackValue generateEqualsForExpressionsOnStack(IElementType opToken, Type leftType, Type rightType) { if (isNumberPrimitive(leftType) && leftType == rightType) { return compareExpressionsOnStack(opToken, leftType); diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index df0860a370c..82799029ab6 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -25,6 +25,7 @@ public class JetTypeMapper { public static final Type TYPE_TYPEINFO = Type.getType(TypeInfo.class); public static final Type TYPE_JET_OBJECT = Type.getType(JetObject.class); public static final Type TYPE_CLASS = Type.getType(Class.class); + public static final Type TYPE_NOTHING = Type.getObjectType("jet/Nothing"); private final JetStandardLibrary standardLibrary; private final BindingContext bindingContext; @@ -289,6 +290,9 @@ public class JetTypeMapper { } public Type mapType(@NotNull final JetType jetType, OwnerKind kind) { + if (jetType.equals(JetStandardClasses.getNothingType()) || jetType.equals(JetStandardClasses.getNullableNothingType())) { + return TYPE_NOTHING; + } if (jetType.equals(standardLibrary.getIntType())) { return Type.INT_TYPE; } diff --git a/idea/src/org/jetbrains/jet/codegen/StackValue.java b/idea/src/org/jetbrains/jet/codegen/StackValue.java index 800bb5be3b7..9a7269853a0 100644 --- a/idea/src/org/jetbrains/jet/codegen/StackValue.java +++ b/idea/src/org/jetbrains/jet/codegen/StackValue.java @@ -282,7 +282,7 @@ public abstract class StackValue { @Override public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { if (value instanceof Boolean) { - boolean boolValue = ((Boolean) value).booleanValue(); + boolean boolValue = (Boolean) value; if (boolValue ^ jumpIfFalse) { v.goTo(label); } diff --git a/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java b/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java index 8dff8181502..50c8649e920 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java @@ -148,4 +148,14 @@ public class ControlStructuresTest extends CodegenTestCase { public void testKt237() throws Exception { blackBoxFile("regressions/kt237.jet"); } + + public void testCompareToNull() throws Exception { + loadText("fun foo(a: String?, b: String?): Boolean = a == null && b !== null"); + String text = generateToText(); + assertTrue(!text.contains("java/lang/Object.equals")); + System.out.println(text); + final Method main = generateFunction(); + assertEquals(true, main.invoke(null, null, "lala")); + assertEquals(false, main.invoke(null, null, null)); + } } From ab63974fc3778938b1984c720c63bc810f2714f1 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Sun, 4 Sep 2011 20:03:38 +0200 Subject: [PATCH 11/19] fix for KT-46 --- .../jet/codegen/ExpressionCodegen.java | 136 +++++++++++------- .../jetbrains/jet/codegen/JetTypeMapper.java | 8 +- .../jet/codegen/ControlStructuresTest.java | 21 ++- .../jet/codegen/NamespaceGenTest.java | 2 + 4 files changed, 113 insertions(+), 54 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 241b8abb1f7..f5cd80ccf2b 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1200,8 +1200,10 @@ public class ExpressionCodegen extends JetVisitor { } private StackValue generateEquals(JetExpression left, JetExpression right, IElementType opToken) { - Type leftType = expressionType(left); - Type rightType = expressionType(right); + JetType leftJetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, left); + Type leftType = typeMapper.mapType(leftJetType); + JetType rightJetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, right); + Type rightType = typeMapper.mapType(rightJetType); if(leftType == JetTypeMapper.TYPE_NOTHING) { return genCmpWithNull(right, rightType, opToken); } @@ -1222,32 +1224,39 @@ public class ExpressionCodegen extends JetVisitor { gen(left, leftType); gen(right, rightType); } - return generateEqualsForExpressionsOnStack(opToken, leftType, rightType); + + if(JetTypeMapper.isPrimitive(leftType)) // both are primitive + return generateEqualsForExpressionsOnStack(opToken, leftType, rightType, false, false); + + return generateEqualsForExpressionsOnStack(opToken, leftType, rightType, leftJetType.isNullable(), rightJetType.isNullable()); } - private StackValue genCmpWithNull(JetExpression exp, Type expType, IElementType opToken) { - gen(exp, typeMapper.boxType(expType)); - Label fail = new Label(), end = new Label(); - if(JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) { - v.ifnonnull(fail); + private StackValue genEqualsOnStack(IElementType opToken) { + v.invokevirtual("java/lang/Object", "equals", "(Ljava/lang/Object;)Z"); + if(opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) { v.iconst(1); - v.goTo(end); - v.mark(fail); - v.iconst(0); - v.mark(end); - } - else { - v.ifnull(fail); - v.iconst(1); - v.goTo(end); - v.mark(fail); - v.iconst(0); - v.mark(end); + v.xor(Type.INT_TYPE); } return StackValue.onStack(Type.BOOLEAN_TYPE); } - private StackValue generateEqualsForExpressionsOnStack(IElementType opToken, Type leftType, Type rightType) { + private StackValue genCmpWithNull(JetExpression exp, Type expType, IElementType opToken) { + v.iconst(1); + gen(exp, typeMapper.boxType(expType)); + Label ok = new Label(); + if(JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) { + v.ifnull(ok); + } + else { + v.ifnonnull(ok); + } + v.pop(); + v.iconst(0); + v.mark(ok); + return StackValue.onStack(Type.BOOLEAN_TYPE); + } + + private StackValue generateEqualsForExpressionsOnStack(IElementType opToken, Type leftType, Type rightType, boolean leftNullable, boolean rightNullable) { if (isNumberPrimitive(leftType) && leftType == rightType) { return compareExpressionsOnStack(opToken, leftType); } @@ -1256,38 +1265,67 @@ public class ExpressionCodegen extends JetVisitor { return StackValue.cmp(opToken, leftType); } else { - return generateNullSafeEquals(opToken); + return generateNullSafeEquals(opToken, leftNullable, rightNullable); } } } - private StackValue generateNullSafeEquals(IElementType opToken) { - v.dup2(); // left right left right - Label rightNull = new Label(); - v.ifnull(rightNull); - Label leftNull = new Label(); - v.ifnull(leftNull); - v.invokevirtual(CLASS_OBJECT, "equals", "(Ljava/lang/Object;)Z"); - Label end = new Label(); - v.goTo(end); - v.mark(rightNull); - // left right left - Label bothNull = new Label(); - v.ifnull(bothNull); - v.mark(leftNull); - v.pop2(); - v.iconst(0); - v.goTo(end); - v.mark(bothNull); - v.pop2(); - v.iconst(1); - v.mark(end); - - final StackValue onStack = StackValue.onStack(Type.BOOLEAN_TYPE); - if (opToken == JetTokens.EXCLEQ) { - return StackValue.not(onStack); + private StackValue generateNullSafeEquals(IElementType opToken, boolean leftNullable, boolean rightNullable) { + if(!leftNullable) { + v.invokevirtual(CLASS_OBJECT, "equals", "(Ljava/lang/Object;)Z"); + if (opToken == JetTokens.EXCLEQ) { + v.iconst(1); + v.xor(Type.INT_TYPE); + } } - return onStack; + else { + if(rightNullable) { + v.dup2(); // left right left right + Label rightNull = new Label(); + v.ifnull(rightNull); + Label leftNull = new Label(); + v.ifnull(leftNull); + v.invokevirtual(CLASS_OBJECT, "equals", "(Ljava/lang/Object;)Z"); + if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) { + v.iconst(1); + v.xor(Type.INT_TYPE); + } + Label end = new Label(); + v.goTo(end); + v.mark(rightNull); + // left right left + Label bothNull = new Label(); + v.ifnull(bothNull); + v.mark(leftNull); + v.pop2(); + v.iconst(opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ ? 1 : 0); + v.goTo(end); + v.mark(bothNull); + v.pop2(); + v.iconst(opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ ? 0 : 1); + v.mark(end); + } + else { + v.dup2(); // left right left right + v.pop(); + Label leftNull = new Label(); + v.ifnull(leftNull); + v.invokevirtual(CLASS_OBJECT, "equals", "(Ljava/lang/Object;)Z"); + if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) { + v.iconst(1); + v.xor(Type.INT_TYPE); + } + Label end = new Label(); + v.goTo(end); + // left right + v.mark(leftNull); + v.pop2(); + v.iconst(opToken == JetTokens.EXCLEQ ? 1 : 0); + v.mark(end); + } + } + + return StackValue.onStack(Type.BOOLEAN_TYPE); } private StackValue generateElvis(JetBinaryExpression expression) { @@ -1747,7 +1785,7 @@ public class ExpressionCodegen extends JetVisitor { JetExpression condExpression = ((JetExpressionPattern) pattern).getExpression(); Type condType = isNumberPrimitive(subjectType) ? expressionType(condExpression) : OBJECT_TYPE; gen(condExpression, condType); - return generateEqualsForExpressionsOnStack(JetTokens.EQEQ, subjectType, condType); + return generateEqualsForExpressionsOnStack(JetTokens.EQEQ, subjectType, condType, false, false); } else if (pattern instanceof JetWildcardPattern) { return StackValue.constant(!negated, Type.BOOLEAN_TYPE); diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 82799029ab6..40522b08121 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -274,22 +274,22 @@ public class JetTypeMapper { return owner; } - public Type mapReturnType(@NotNull final JetType jetType, OwnerKind kind) { + @NotNull public Type mapReturnType(@NotNull final JetType jetType, OwnerKind kind) { if (jetType.equals(JetStandardClasses.getUnitType()) || jetType.equals(JetStandardClasses.getNothingType())) { return Type.VOID_TYPE; } return mapType(jetType, kind); } - public Type mapReturnType(final JetType jetType) { + @NotNull public Type mapReturnType(final JetType jetType) { return mapReturnType(jetType, OwnerKind.INTERFACE); } - public Type mapType(final JetType jetType) { + @NotNull public Type mapType(final JetType jetType) { return mapType(jetType, OwnerKind.INTERFACE); } - public Type mapType(@NotNull final JetType jetType, OwnerKind kind) { + @NotNull public Type mapType(@NotNull final JetType jetType, OwnerKind kind) { if (jetType.equals(JetStandardClasses.getNothingType()) || jetType.equals(JetStandardClasses.getNullableNothingType())) { return TYPE_NOTHING; } diff --git a/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java b/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java index 50c8649e920..47abe0a954c 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java @@ -150,7 +150,7 @@ public class ControlStructuresTest extends CodegenTestCase { } public void testCompareToNull() throws Exception { - loadText("fun foo(a: String?, b: String?): Boolean = a == null && b !== null"); + loadText("fun foo(a: String?, b: String?): Boolean = a == null && b !== null && null == a && null !== b"); String text = generateToText(); assertTrue(!text.contains("java/lang/Object.equals")); System.out.println(text); @@ -158,4 +158,23 @@ public class ControlStructuresTest extends CodegenTestCase { assertEquals(true, main.invoke(null, null, "lala")); assertEquals(false, main.invoke(null, null, null)); } + + public void testCompareToNonnullableEq() throws Exception { + loadText("fun foo(a: String?, b: String): Boolean = a == b || b == a"); + String text = generateToText(); + System.out.println(text); + final Method main = generateFunction(); + assertEquals(false, main.invoke(null, null, "lala")); + assertEquals(true, main.invoke(null, "papa", "papa")); + } + + public void testCompareToNonnullableNotEq() throws Exception { + loadText("fun foo(a: String?, b: String): Boolean = a != b"); + String text = generateToText(); + System.out.println(text); + assertTrue(text.contains("IXOR")); + final Method main = generateFunction(); + assertEquals(true, main.invoke(null, null, "lala")); + assertEquals(false, main.invoke(null, "papa", "papa")); + } } diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index 341818a2fb7..437b57a6096 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -209,6 +209,7 @@ public class NamespaceGenTest extends CodegenTestCase { public void testJavaEqualsNull() throws Exception { loadText("fun foo(s1: String?, s2: String?) = s1 == s2"); final Method main = generateFunction(); + System.out.println(generateToText()); assertEquals(Boolean.TRUE, main.invoke(null, null, null)); assertEquals(Boolean.FALSE, main.invoke(null, "jet", null)); assertEquals(Boolean.FALSE, main.invoke(null, null, "jet")); @@ -217,6 +218,7 @@ public class NamespaceGenTest extends CodegenTestCase { public void testEqualsNullLiteral() throws Exception { loadText("fun foo(s: String?) = s == null"); final Method main = generateFunction(); + System.out.println(generateToText()); assertEquals(Boolean.TRUE, main.invoke(null, new Object[] { null })); assertEquals(Boolean.FALSE, main.invoke(null, "jet")); } From 232fc89cca08dea8648c8ee1b6cb274a40876cf5 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Mon, 5 Sep 2011 08:18:51 +0200 Subject: [PATCH 12/19] fix for KT-80 --- .../jet/codegen/ExpressionCodegen.java | 57 +++++++++++++++++-- .../org/jetbrains/jet/codegen/StackValue.java | 14 ++++- .../codegen/patternMatching/range.jet | 13 ++++- .../jet/codegen/PatternMatchingTest.java | 4 ++ 4 files changed, 78 insertions(+), 10 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index f5cd80ccf2b..493730ebc98 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -809,7 +809,7 @@ public class ExpressionCodegen extends JetVisitor { v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : isInterface ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL, owner, functionDescriptor.getName(), typeMapper.mapSignature(functionDescriptor.getName(),functionDescriptor).getDescriptor()); StackValue.onStack(typeMapper.mapType(functionDescriptor.getReturnType())).coerce(type, v); } - + public StackValue intermediateValueForProperty(PropertyDescriptor propertyDescriptor, final boolean forceField, boolean forceInterface) { DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); boolean isStatic = containingDeclaration instanceof NamespaceDescriptorImpl; @@ -1990,11 +1990,42 @@ public class ExpressionCodegen extends JetVisitor { @Nullable Label nextEntry) { StackValue conditionValue; if (condition instanceof JetWhenConditionInRange) { - JetExpression range = ((JetWhenConditionInRange) condition).getRangeExpression(); - gen(range, RANGE_TYPE); - new StackValue.Local(subjectLocal, subjectType).put(INTEGER_TYPE, v); - v.invokeinterface(CLASS_RANGE, "contains", "(Ljava/lang/Comparable;)Z"); - conditionValue = new StackValue.OnStack(Type.BOOLEAN_TYPE); + JetWhenConditionInRange conditionInRange = (JetWhenConditionInRange) condition; + JetExpression rangeExpression = conditionInRange.getRangeExpression(); + if(isIntRangeExpr(rangeExpression)) { + v.iconst(1); + //noinspection ConstantConditions + new StackValue.Local(subjectLocal, subjectType).put(Type.INT_TYPE, v); + JetBinaryExpression binaryExpression = (JetBinaryExpression) rangeExpression; + gen(binaryExpression.getLeft(), Type.INT_TYPE); + Label lok = new Label(); + v.ificmpge(lok); + v.pop(); + v.iconst(0); + v.mark(lok); + + v.iconst(1); + new StackValue.Local(subjectLocal, subjectType).put(Type.INT_TYPE, v); + gen(binaryExpression.getRight(), Type.INT_TYPE); + Label rok = new Label(); + v.ificmple(rok); + v.pop(); + v.iconst(0); + v.mark(rok); + + v.and(Type.INT_TYPE); + if(conditionInRange.getOperationReference().getReferencedNameElementType() == JetTokens.NOT_IN) { + v.iconst(1); + v.xor(Type.INT_TYPE); + } + } + else { + FunctionDescriptor op = (FunctionDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, conditionInRange.getOperationReference()); + genToJVMStack(rangeExpression); + new StackValue.Local(subjectLocal, subjectType).put(JetTypeMapper.TYPE_OBJECT, v); + invokeFunctionNoParams(op, Type.BOOLEAN_TYPE, v); + } + return StackValue.onStack(Type.BOOLEAN_TYPE); } else if (condition instanceof JetWhenConditionIsPattern) { JetWhenConditionIsPattern patternCondition = (JetWhenConditionIsPattern) condition; @@ -2032,6 +2063,20 @@ public class ExpressionCodegen extends JetVisitor { return conditionValue; } + private boolean isIntRangeExpr(JetExpression rangeExpression) { + if(rangeExpression instanceof JetBinaryExpression) { + JetBinaryExpression binaryExpression = (JetBinaryExpression) rangeExpression; + if (binaryExpression.getOperationReference().getReferencedNameElementType() == JetTokens.RANGE) { + JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, rangeExpression); + final DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); + if (isClass(descriptor, "IntRange")) { // TODO IntRange subclasses + return true; + } + } + } + return false ; + } + @Override public StackValue visitTupleExpression(JetTupleExpression expression, StackValue receiver) { final List entries = expression.getEntries(); diff --git a/idea/src/org/jetbrains/jet/codegen/StackValue.java b/idea/src/org/jetbrains/jet/codegen/StackValue.java index 9a7269853a0..6ff96e485c3 100644 --- a/idea/src/org/jetbrains/jet/codegen/StackValue.java +++ b/idea/src/org/jetbrains/jet/codegen/StackValue.java @@ -275,7 +275,19 @@ public abstract class StackValue { @Override public void put(Type type, InstructionAdapter v) { - v.aconst(value); + if(value instanceof Integer) + v.iconst((Integer) value); + else + if(value instanceof Long) + v.lconst((Long) value); + else + if(value instanceof Float) + v.fconst((Float) value); + else + if(value instanceof Double) + v.dconst((Double) value); + else + v.aconst(value); coerce(type, v); } diff --git a/idea/testData/codegen/patternMatching/range.jet b/idea/testData/codegen/patternMatching/range.jet index 329a4234971..5010f350b68 100644 --- a/idea/testData/codegen/patternMatching/range.jet +++ b/idea/testData/codegen/patternMatching/range.jet @@ -1,4 +1,11 @@ -fun isDigit(a: Int) = when(a) { - in 0..9 => "digit" - else => "something" +fun isDigit(a: Int) : String { + val aa = java.util.ArrayList () + aa.add(239) + + return when(a) { + in aa => "array list" + in 0..9 => "digit" + !in 0..100 => "not small" + else => "something" + } } diff --git a/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java b/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java index 98a29598db0..29637ec910a 100644 --- a/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java @@ -39,8 +39,12 @@ public class PatternMatchingTest extends CodegenTestCase { loadFile(); System.out.println(generateToText()); Method foo = generateFunction(); + assertEquals("array list", foo.invoke(null, 239)); + assertEquals("digit", foo.invoke(null, 0)); assertEquals("digit", foo.invoke(null, 9)); + assertEquals("digit", foo.invoke(null, 5)); assertEquals("something", foo.invoke(null, 19)); + assertEquals("not small", foo.invoke(null, 190)); } public void testRangeChar() throws Exception { From eb82967860faf3ac60f72a57ef1376651ba0f935 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Mon, 5 Sep 2011 10:25:25 +0200 Subject: [PATCH 13/19] fix for KT-277 --- .../jet/codegen/ExpressionCodegen.java | 90 +++++++++++++------ .../codegen/patternMatching/inrange.jet | 9 ++ .../jet/codegen/PatternMatchingTest.java | 12 +++ 3 files changed, 84 insertions(+), 27 deletions(-) create mode 100644 idea/testData/codegen/patternMatching/inrange.jet diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 493730ebc98..16428d639f9 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1155,6 +1155,9 @@ public class ExpressionCodegen extends JetVisitor { else if (opToken == JetTokens.ELVIS) { return generateElvis(expression); } + else if(opToken == JetTokens.IN_KEYWORD || opToken == JetTokens.NOT_IN) { + return generateIn (expression); + } else { DeclarationDescriptor op = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference()); final Callable callable = resolveToCallable(op); @@ -1173,6 +1176,64 @@ public class ExpressionCodegen extends JetVisitor { } } + private StackValue generateIn(JetBinaryExpression expression) { + JetExpression expr = expression.getLeft(); + StackValue leftValue = gen(expr); + if(isIntRangeExpr(expression.getRight())) { + JetBinaryExpression rangeExpression = (JetBinaryExpression) expression.getRight(); + boolean inverted = expression.getOperationReference().getReferencedNameElementType() == JetTokens.NOT_IN; + getInIntTest(leftValue, rangeExpression, inverted); + } + else { + leftValue.put(JetTypeMapper.TYPE_OBJECT, v); + genToJVMStack(expression.getRight()); + v.swap(); + FunctionDescriptor op = (FunctionDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference()); + invokeFunctionNoParams(op, Type.BOOLEAN_TYPE, v); + } + return StackValue.onStack(Type.BOOLEAN_TYPE); + } + + private void getInIntTest(StackValue leftValue, JetBinaryExpression rangeExpression, boolean inverted) { + v.iconst(1); + // 1 + leftValue.put(Type.INT_TYPE, v); + // 1 l + v.dup2(); + // 1 l 1 l + + //noinspection ConstantConditions + gen(rangeExpression.getLeft(), Type.INT_TYPE); + // 1 l 1 l r + Label lok = new Label(); + v.ificmpge(lok); + // 1 l 1 + v.pop(); + v.iconst(0); + v.mark(lok); + // 1 l c + v.dupX2(); + // c 1 l c + v.pop(); + // c 1 l + + gen(rangeExpression.getRight(), Type.INT_TYPE); + // c 1 l r + Label rok = new Label(); + v.ificmple(rok); + // c 1 + v.pop(); + v.iconst(0); + v.mark(rok); + // c c + + v.and(Type.INT_TYPE); + if(inverted) { + v.iconst(1); + v.xor(Type.INT_TYPE); + } + } + private StackValue generateBooleanAnd(JetBinaryExpression expression) { gen(expression.getLeft(), Type.BOOLEAN_TYPE); Label ifFalse = new Label(); @@ -1986,38 +2047,13 @@ public class ExpressionCodegen extends JetVisitor { return StackValue.onStack(expressionType(expression)); } - private StackValue generateWhenCondition(Type subjectType, int subjectLocal, JetWhenCondition condition, - @Nullable Label nextEntry) { + private StackValue generateWhenCondition(Type subjectType, int subjectLocal, JetWhenCondition condition, @Nullable Label nextEntry) { StackValue conditionValue; if (condition instanceof JetWhenConditionInRange) { JetWhenConditionInRange conditionInRange = (JetWhenConditionInRange) condition; JetExpression rangeExpression = conditionInRange.getRangeExpression(); if(isIntRangeExpr(rangeExpression)) { - v.iconst(1); - //noinspection ConstantConditions - new StackValue.Local(subjectLocal, subjectType).put(Type.INT_TYPE, v); - JetBinaryExpression binaryExpression = (JetBinaryExpression) rangeExpression; - gen(binaryExpression.getLeft(), Type.INT_TYPE); - Label lok = new Label(); - v.ificmpge(lok); - v.pop(); - v.iconst(0); - v.mark(lok); - - v.iconst(1); - new StackValue.Local(subjectLocal, subjectType).put(Type.INT_TYPE, v); - gen(binaryExpression.getRight(), Type.INT_TYPE); - Label rok = new Label(); - v.ificmple(rok); - v.pop(); - v.iconst(0); - v.mark(rok); - - v.and(Type.INT_TYPE); - if(conditionInRange.getOperationReference().getReferencedNameElementType() == JetTokens.NOT_IN) { - v.iconst(1); - v.xor(Type.INT_TYPE); - } + getInIntTest(new StackValue.Local(subjectLocal, subjectType), (JetBinaryExpression) rangeExpression, conditionInRange.getOperationReference().getReferencedNameElementType() == JetTokens.NOT_IN); } else { FunctionDescriptor op = (FunctionDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, conditionInRange.getOperationReference()); diff --git a/idea/testData/codegen/patternMatching/inrange.jet b/idea/testData/codegen/patternMatching/inrange.jet new file mode 100644 index 00000000000..e883e5dbb9c --- /dev/null +++ b/idea/testData/codegen/patternMatching/inrange.jet @@ -0,0 +1,9 @@ +fun isDigit(a: Int) : String { + val aa = java.util.ArrayList () + aa.add(239) + + if(a in aa) return "array list" + if(a in 0..9) return "digit" + if(a !in 0..100) return "not small" + return "something" +} diff --git a/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java b/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java index 29637ec910a..13aaf4b19e2 100644 --- a/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java @@ -35,6 +35,18 @@ public class PatternMatchingTest extends CodegenTestCase { assertEquals("something", foo.invoke(null, new Object())); } + public void testInrange() throws Exception { + loadFile(); + System.out.println(generateToText()); + Method foo = generateFunction(); + assertEquals("array list", foo.invoke(null, 239)); + assertEquals("digit", foo.invoke(null, 0)); + assertEquals("digit", foo.invoke(null, 9)); + assertEquals("digit", foo.invoke(null, 5)); + assertEquals("not small", foo.invoke(null, 190)); + assertEquals("something", foo.invoke(null, 19)); + } + public void testRange() throws Exception { loadFile(); System.out.println(generateToText()); From a8a438ffd324e90fe103171a40df7eb5bd20dcbd Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Mon, 5 Sep 2011 13:47:54 +0200 Subject: [PATCH 14/19] fix for KT-48 --- .../codegen/ImplementationBodyCodegen.java | 36 +++++++++++++- .../AnnotationArgumentVisitor.java | 2 + .../lang/resolve/constants/FloatValue.java | 38 +++++++++++++++ .../jet/lang/types/JetTypeInferrer.java | 47 +++++++++++++++++-- idea/testData/codegen/regressions/kt48.jet | 29 ++++++++++++ .../jetbrains/jet/codegen/ClassGenTest.java | 5 ++ 6 files changed, 152 insertions(+), 5 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/lang/resolve/constants/FloatValue.java create mode 100644 idea/testData/codegen/regressions/kt48.jet diff --git a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 7ce0246dccd..8a84bdb69a7 100644 --- a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -6,6 +6,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lexer.JetTokens; import org.objectweb.asm.ClassVisitor; @@ -413,8 +414,41 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { if (state.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) { final JetExpression initializer = ((JetProperty) declaration).getInitializer(); if (initializer != null) { + CompileTimeConstant compileTimeValue = state.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, initializer); + if(compileTimeValue != null) { + assert compileTimeValue != null; + Object value = compileTimeValue.getValue(); + Type type = state.getTypeMapper().mapType(propertyDescriptor.getOutType()); + if(JetTypeMapper.isPrimitive(type)) { + if( !propertyDescriptor.getOutType().isNullable() && value instanceof Number) { + if(type == Type.INT_TYPE && ((Number)value).intValue() == 0) + continue; + if(type == Type.BYTE_TYPE && ((Number)value).byteValue() == 0) + continue; + if(type == Type.LONG_TYPE && ((Number)value).longValue() == 0L) + continue; + if(type == Type.SHORT_TYPE && ((Number)value).shortValue() == 0) + continue; + if(type == Type.DOUBLE_TYPE && ((Number)value).doubleValue() == 0d) + continue; + if(type == Type.FLOAT_TYPE && ((Number)value).byteValue() == 0f) + continue; + } + if(type == Type.BOOLEAN_TYPE && value instanceof Boolean && !((Boolean)value)) + continue; + if(type == Type.CHAR_TYPE && value instanceof Character && ((Character)value) == 0) + continue; + } + else { + if(value == null) + continue; + } + } iv.load(0, JetTypeMapper.TYPE_OBJECT); - codegen.genToJVMStack(initializer); + Type type = codegen.expressionType(initializer); + if(propertyDescriptor.getOutType().isNullable()) + type = state.getTypeMapper().boxType(type); + codegen.gen(initializer, type); codegen.intermediateValueForProperty(propertyDescriptor, false, false).store(iv); } diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/annotations/AnnotationArgumentVisitor.java b/idea/src/org/jetbrains/jet/lang/descriptors/annotations/AnnotationArgumentVisitor.java index 70057d05f38..6443c23e9cb 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/annotations/AnnotationArgumentVisitor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/annotations/AnnotationArgumentVisitor.java @@ -19,6 +19,8 @@ public interface AnnotationArgumentVisitor { R visitDoubleValue(DoubleValue value, D data); + R visitFloatValue(FloatValue value, D data); + R visitBooleanValue(BooleanValue value, D data); R visitCharValue(CharValue value, D data); diff --git a/idea/src/org/jetbrains/jet/lang/resolve/constants/FloatValue.java b/idea/src/org/jetbrains/jet/lang/resolve/constants/FloatValue.java new file mode 100644 index 00000000000..5f8442cca26 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/resolve/constants/FloatValue.java @@ -0,0 +1,38 @@ +package org.jetbrains.jet.lang.resolve.constants; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationArgumentVisitor; +import org.jetbrains.jet.lang.types.JetStandardLibrary; +import org.jetbrains.jet.lang.types.JetType; + +/** + * @author alex.tkachman + */ +public class FloatValue implements CompileTimeConstant { + private final float value; + + public FloatValue(float value) { + this.value = value; + } + + @Override + public Float getValue() { + return value; + } + + @NotNull + @Override + public JetType getType(@NotNull JetStandardLibrary standardLibrary) { + return standardLibrary.getFloatType(); + } + + @Override + public R accept(AnnotationArgumentVisitor visitor, D data) { + return visitor.visitFloatValue(this, data); + } + + @Override + public String toString() { + return value + ".flt"; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 0e637764a7b..1ae384663f7 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -18,10 +18,7 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.*; -import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; -import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver; -import org.jetbrains.jet.lang.resolve.constants.ErrorValue; -import org.jetbrains.jet.lang.resolve.constants.StringValue; +import org.jetbrains.jet.lang.resolve.constants.*; import org.jetbrains.jet.lang.types.inference.ConstraintSystem; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.resolve.DescriptorRenderer; @@ -35,6 +32,17 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.*; * @author abreslav */ public class JetTypeInferrer { + + private static final Set numberConversions = new HashSet(); + + static { + numberConversions.add("dbl"); + numberConversions.add("flt"); + numberConversions.add("lng"); + numberConversions.add("sht"); + numberConversions.add("byt"); + numberConversions.add("int"); + } private static final JetType FORBIDDEN = new JetType() { @NotNull @@ -2156,7 +2164,38 @@ public class JetTypeInferrer { // TODO : functions as values JetExpression selectorExpression = expression.getSelectorExpression(); JetExpression receiverExpression = expression.getReceiverExpression(); + JetType receiverType = context.services.typeInferrerVisitorWithNamespaces.getType(receiverExpression, new TypeInferenceContext(context.trace, context.scope, false, context.dataFlowInfo, NO_EXPECTED_TYPE, NO_EXPECTED_TYPE)); + + if(selectorExpression instanceof JetSimpleNameExpression) { + CompileTimeConstant compileTimeConstant = context.trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, receiverExpression); + CompileTimeConstant expressionCompileTimeConstant = context.trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, expression); + if(expressionCompileTimeConstant == null && compileTimeConstant != null && compileTimeConstant.getValue() instanceof Number) { + Number value = (Number) compileTimeConstant.getValue(); + String referencedName = ((JetSimpleNameExpression) selectorExpression).getReferencedName(); + if(numberConversions.contains(referencedName)) { + if("dbl".equals(referencedName)) { + context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new DoubleValue(value.doubleValue())); + } + else if("flt".equals(referencedName)) { + context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new FloatValue(value.floatValue())); + } + else if("lng".equals(referencedName)) { + context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new LongValue(value.longValue())); + } + else if("sht".equals(referencedName)) { + context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new ShortValue(value.shortValue())); + } + else if("byt".equals(referencedName)) { + context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new ByteValue(value.byteValue())); + } + else if("byt".equals(referencedName)) { + context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new IntValue(value.intValue())); + } + } + } + } + if (receiverType == null) return null; // Clean resolution: no autocasts diff --git a/idea/testData/codegen/regressions/kt48.jet b/idea/testData/codegen/regressions/kt48.jet new file mode 100644 index 00000000000..8a0126def52 --- /dev/null +++ b/idea/testData/codegen/regressions/kt48.jet @@ -0,0 +1,29 @@ +class A() { + var xi = 0 + var xin : Int? = 0 + var xinn : Int? = null + + var xl = 0.lng + var xln : Long? = 0.lng + var xlnn : Long? = null + + var xb = 0.byt + var xbn : Long? = 0.byt + var xbnn : Long? = null + + var xf = 0.flt + var xfn : Float? = 0.flt + var xfnn : Float? = null + + var xd = 0.dbl + var xdn : Double? = 0.dbl + var xdnn : Double? = null + + var xs = 0.sht + var xsn : Short? = 0.sht + var xsnn : Short? = null +} + +fun box() : String { + return "OK" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java index 8a17b3d4887..b215854c0ab 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -172,4 +172,9 @@ public class ClassGenTest extends CodegenTestCase { public void testKt249() throws Exception { blackBoxFile("regressions/kt249.jet"); } + + public void testKt48 () throws Exception { + blackBoxFile("regressions/kt48.jet"); + System.out.println(generateToText()); + } } From a6d71f93611be9b9db9a81d30266d3a5dfdb6cdd Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Mon, 5 Sep 2011 13:58:29 +0200 Subject: [PATCH 15/19] test for KT-160 --- idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java b/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java index f6621b37e98..9747ba38bc0 100644 --- a/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java @@ -134,4 +134,10 @@ public class PropertyGenTest extends CodegenTestCase { public void testKt257 () throws Exception { blackBoxFile("regressions/kt257.jet"); } + + public void testKt160() throws Exception { + loadText("public val s = java.lang.Double.toString(1.0)"); + final Method method = generateFunction("getS"); + assertEquals(method.invoke(null), "1.0"); + } } From 21243979ab8ec9ff46af9881c5796d100f6e4d5b Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 5 Sep 2011 16:23:30 +0400 Subject: [PATCH 16/19] Line numbers removed from messages Value handling fixed --- .../jet/lang/types/JetTypeInferrer.java | 67 ++++++++++--------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 1ae384663f7..12a60369742 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -11,7 +11,6 @@ import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; -import org.jetbrains.jet.lang.ErrorHandler; import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; import org.jetbrains.jet.lang.descriptors.*; @@ -19,6 +18,7 @@ import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.constants.*; +import org.jetbrains.jet.lang.resolve.constants.StringValue; import org.jetbrains.jet.lang.types.inference.ConstraintSystem; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.resolve.DescriptorRenderer; @@ -344,7 +344,7 @@ public class JetTypeInferrer { case SINGLE_FUNCTION_ARGUMENT_MISMATCH: if (argumentList != null) { // TODO : More helpful message. NOTE: there's a separate handling for this for constructors - trace.getErrorHandler().genericError(argumentList.getNode(), "Arguments do not match " + DescriptorRenderer.TEXT.render(resolutionResult.getFunctionDescriptor()) + " " + ErrorHandler.atLocation(referenceExpression)); + trace.getErrorHandler().genericError(argumentList.getNode(), "Arguments do not match " + DescriptorRenderer.TEXT.render(resolutionResult.getFunctionDescriptor())); } else { trace.getErrorHandler().unresolvedReference(referenceExpression); @@ -1196,7 +1196,7 @@ public class JetTypeInferrer { type = context.typeResolver.resolveType(context.scope, typeReference); } else { - context.trace.getErrorHandler().genericError(parameter.getNode(), "Type inference for parameters is not implemented yet " + ErrorHandler.atLocation(parameter.getNavigationElement())); + context.trace.getErrorHandler().genericError(parameter.getNode(), "Type inference for parameters is not implemented yet "); type = ErrorUtils.createErrorType("Not inferred"); } ValueParameterDescriptor valueParameterDescriptor = context.classDescriptorResolver.resolveValueParameterDescriptor(functionDescriptor, parameter, i, type); @@ -1717,7 +1717,7 @@ public class JetTypeInferrer { return; } if (TypeUtils.intersect(semanticServices.getTypeChecker(), Sets.newHashSet(type, subjectType)) == null) { - context.trace.getErrorHandler().genericError(reportErrorOn.getNode(), "Incompatible types: " + type + " and " + subjectType + " " + ErrorHandler.atLocation(reportErrorOn)); + context.trace.getErrorHandler().genericError(reportErrorOn.getNode(), "Incompatible types: " + type + " and " + subjectType); } } @@ -2167,33 +2167,8 @@ public class JetTypeInferrer { JetType receiverType = context.services.typeInferrerVisitorWithNamespaces.getType(receiverExpression, new TypeInferenceContext(context.trace, context.scope, false, context.dataFlowInfo, NO_EXPECTED_TYPE, NO_EXPECTED_TYPE)); - if(selectorExpression instanceof JetSimpleNameExpression) { - CompileTimeConstant compileTimeConstant = context.trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, receiverExpression); - CompileTimeConstant expressionCompileTimeConstant = context.trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, expression); - if(expressionCompileTimeConstant == null && compileTimeConstant != null && compileTimeConstant.getValue() instanceof Number) { - Number value = (Number) compileTimeConstant.getValue(); - String referencedName = ((JetSimpleNameExpression) selectorExpression).getReferencedName(); - if(numberConversions.contains(referencedName)) { - if("dbl".equals(referencedName)) { - context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new DoubleValue(value.doubleValue())); - } - else if("flt".equals(referencedName)) { - context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new FloatValue(value.floatValue())); - } - else if("lng".equals(referencedName)) { - context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new LongValue(value.longValue())); - } - else if("sht".equals(referencedName)) { - context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new ShortValue(value.shortValue())); - } - else if("byt".equals(referencedName)) { - context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new ByteValue(value.byteValue())); - } - else if("byt".equals(referencedName)) { - context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new IntValue(value.intValue())); - } - } - } + if (selectorExpression instanceof JetSimpleNameExpression) { + propagateConstantValues(expression, context, (JetSimpleNameExpression) selectorExpression); } if (receiverType == null) return null; @@ -2267,6 +2242,36 @@ public class JetTypeInferrer { return context.services.checkType(result, expression, contextWithExpectedType); } + private void propagateConstantValues(JetQualifiedExpression expression, TypeInferenceContext context, JetSimpleNameExpression selectorExpression) { + JetExpression receiverExpression = expression.getReceiverExpression(); + CompileTimeConstant receiverValue = context.trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, receiverExpression); + CompileTimeConstant wholeExpressionValue = context.trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, expression); + if (wholeExpressionValue == null && receiverValue != null && !(receiverValue instanceof ErrorValue) && receiverValue.getValue() instanceof Number) { + Number value = (Number) receiverValue.getValue(); + String referencedName = selectorExpression.getReferencedName(); + if (numberConversions.contains(referencedName)) { + if ("dbl".equals(referencedName)) { + context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new DoubleValue(value.doubleValue())); + } + else if ("flt".equals(referencedName)) { + context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new FloatValue(value.floatValue())); + } + else if ("lng".equals(referencedName)) { + context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new LongValue(value.longValue())); + } + else if ("sht".equals(referencedName)) { + context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new ShortValue(value.shortValue())); + } + else if ("byt".equals(referencedName)) { + context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new ByteValue(value.byteValue())); + } + else if ("int".equals(referencedName)) { + context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new IntValue(value.intValue())); + } + } + } + } + @NotNull private FunctionDescriptor getCalleeFunctionDescriptor(@NotNull JetExpression selectorExpression, final TypeInferenceContext context) { From dc3b515451d325a9d9d45ce6e9d5e348f9897c0e Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Mon, 5 Sep 2011 15:05:12 +0200 Subject: [PATCH 17/19] some cleanup --- idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 16428d639f9..311072dedee 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -40,17 +40,13 @@ public class ExpressionCodegen extends JetVisitor { public static final String CLASS_STRING_BUILDER = "java/lang/StringBuilder"; private static final String CLASS_COMPARABLE = "java/lang/Comparable"; - private static final String CLASS_RANGE = "jet/Range"; private static final String CLASS_NO_PATTERN_MATCHED_EXCEPTION = "jet/NoPatternMatchedException"; private static final String CLASS_TYPE_CAST_EXCEPTION = "jet/TypeCastException"; private static final Type OBJECT_TYPE = Type.getType(Object.class); - private static final Type INTEGER_TYPE = Type.getType(Integer.class); private static final Type THROWABLE_TYPE = Type.getType(Throwable.class); private static final Type STRING_TYPE = Type.getObjectType(CLASS_STRING); - private static final Type RANGE_TYPE = Type.getType(Range.class); - private final Stack