From 79ba46700e733e83961bd3d5f55daaa12ed329db Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Fri, 7 Oct 2011 12:18:15 +0200 Subject: [PATCH 01/14] KT-309 --- .../src/org/jetbrains/jet/codegen/JetTypeMapper.java | 3 +++ idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 61a1584b381..2b6513a7a0f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -317,6 +317,9 @@ public class JetTypeMapper { if (jetType.equals(JetStandardClasses.getUnitType()) || jetType.equals(JetStandardClasses.getNothingType())) { return Type.VOID_TYPE; } + if (jetType.equals(JetStandardClasses.getNullableNothingType())) { + return TYPE_OBJECT; + } return mapType(jetType, kind); } diff --git a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java index 4e6f7802f56..17e5d4f9252 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -178,4 +178,11 @@ public class ClassGenTest extends CodegenTestCase { blackBoxFile("regressions/kt48.jet"); System.out.println(generateToText()); } + + public void testKt309 () throws Exception { + loadText("fun box() = null"); + final Method method = generateFunction("box"); + assertEquals(method.getReturnType().getName(), "java.lang.Object"); + System.out.println(generateToText()); + } } From 60f0c98720cbd958e8ff7d6884c4643fb9e1c79e Mon Sep 17 00:00:00 2001 From: svtk Date: Fri, 7 Oct 2011 19:37:15 +0400 Subject: [PATCH 02/14] Added 'inline' keyword --- .../org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java | 2 -- .../src/org/jetbrains/jet/lang/types/JetTypeInferrer.java | 5 +++++ compiler/frontend/src/org/jetbrains/jet/lexer/JetTokens.java | 5 +++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 5c6a6707b46..95b3aa92012 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -91,11 +91,9 @@ public class JetControlFlowProcessor { } private class CFPVisitor extends JetVisitorVoid { -// private final boolean preferBlock; private final boolean inCondition; private CFPVisitor(boolean inCondition) { -// this.preferBlock = preferBlock; this.inCondition = inCondition; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 0f31a0bc99d..58f3149be7e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -2771,6 +2771,11 @@ public class JetTypeInferrer { return context.services.checkType(functionDescriptor.getReturnType(), arrayAccessExpression, context); } + @Override + public JetType visitAnnotatedExpression(JetAnnotatedExpression expression, TypeInferenceContext data) { + return getType(expression.getBaseExpression(), data); + } + @Override public JetType visitJetElement(JetElement element, TypeInferenceContext context) { context.trace.report(UNSUPPORTED.on(element, "in a block")); diff --git a/compiler/frontend/src/org/jetbrains/jet/lexer/JetTokens.java b/compiler/frontend/src/org/jetbrains/jet/lexer/JetTokens.java index 476d1e20751..1322d09776c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lexer/JetTokens.java +++ b/compiler/frontend/src/org/jetbrains/jet/lexer/JetTokens.java @@ -136,6 +136,7 @@ public interface JetTokens { JetKeywordToken CATCH_KEYWORD = JetKeywordToken.softKeyword("catch"); JetKeywordToken OUT_KEYWORD = JetKeywordToken.softKeyword("out"); JetKeywordToken VARARG_KEYWORD = JetKeywordToken.softKeyword("vararg"); + JetKeywordToken INLINE_KEYWORD = JetKeywordToken.softKeyword("inline"); JetKeywordToken FINALLY_KEYWORD = JetKeywordToken.softKeyword("finally"); JetKeywordToken FINAL_KEYWORD = JetKeywordToken.softKeyword("final"); @@ -155,12 +156,12 @@ public interface JetTokens { TokenSet SOFT_KEYWORDS = TokenSet.create(IMPORT_KEYWORD, WHERE_KEYWORD, BY_KEYWORD, GET_KEYWORD, SET_KEYWORD, ABSTRACT_KEYWORD, ENUM_KEYWORD, OPEN_KEYWORD, ANNOTATION_KEYWORD, OVERRIDE_KEYWORD, PRIVATE_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD, PROTECTED_KEYWORD, - CATCH_KEYWORD, FINALLY_KEYWORD, REF_KEYWORD, OUT_KEYWORD, FINAL_KEYWORD, VARARG_KEYWORD + CATCH_KEYWORD, FINALLY_KEYWORD, REF_KEYWORD, OUT_KEYWORD, FINAL_KEYWORD, VARARG_KEYWORD, INLINE_KEYWORD ); TokenSet MODIFIER_KEYWORDS = TokenSet.create(ABSTRACT_KEYWORD, ENUM_KEYWORD, OPEN_KEYWORD, ANNOTATION_KEYWORD, OVERRIDE_KEYWORD, PRIVATE_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD, - PROTECTED_KEYWORD, REF_KEYWORD, OUT_KEYWORD, IN_KEYWORD, FINAL_KEYWORD, VARARG_KEYWORD + PROTECTED_KEYWORD, REF_KEYWORD, OUT_KEYWORD, IN_KEYWORD, FINAL_KEYWORD, VARARG_KEYWORD, INLINE_KEYWORD ); TokenSet WHITE_SPACE_OR_COMMENT_BIT_SET = TokenSet.create(WHITE_SPACE, BLOCK_COMMENT, EOL_COMMENT, DOC_COMMENT); TokenSet WHITESPACES = TokenSet.create(TokenType.WHITE_SPACE); From 78e913762f56d659426e1a0b48aedfa136b53741 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Sat, 8 Oct 2011 09:42:25 +0200 Subject: [PATCH 03/14] arrays iterators --- .../jet/codegen/ExpressionCodegen.java | 14 +- .../jetbrains/jet/codegen/JetTypeMapper.java | 36 +-- .../org/jetbrains/jet/codegen/StackValue.java | 3 + .../jet/codegen/intrinsics/ArrayIterator.java | 65 +++++ .../codegen/intrinsics/IntrinsicMethods.java | 11 + compiler/frontend/src/jet/Library.jet | 2 +- .../jet/lang/types/JetStandardLibrary.java | 3 +- .../jetbrains/jet/codegen/ArrayGenTest.java | 28 ++ stdlib/src/jet/arrays/ArrayIterator.java | 274 ++++++++++++++++++ 9 files changed, 410 insertions(+), 26 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIterator.java create mode 100644 stdlib/src/jet/arrays/ArrayIterator.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 91c126fd77d..6caf932976d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -52,8 +52,10 @@ public class ExpressionCodegen extends JetVisitor { private final InstructionAdapter v; private final FrameMap myMap; private final JetTypeMapper typeMapper; + private final GenerationState state; private final Type returnType; + private final BindingContext bindingContext; private final Map typeParameterExpressions = new HashMap(); private final ClassContext context; @@ -74,6 +76,14 @@ public class ExpressionCodegen extends JetVisitor { this.intrinsics = state.getIntrinsics(); } + public GenerationState getState() { + return state; + } + + public BindingContext getBindingContext() { + return bindingContext; + } + public JetTypeMapper getTypeMapper() { return state.getTypeMapper(); } @@ -921,7 +931,7 @@ public class ExpressionCodegen extends JetVisitor { callableMethod = ClosureCodegen.asCallableMethod((FunctionDescriptor) fd); } else if (fd instanceof FunctionDescriptor) { - callableMethod = ClosureCodegen.asCallableMethod((FunctionDescriptor) fd); + callableMethod = typeMapper.mapToCallableMethod((FunctionDescriptor) fd, null); } else { throw new UnsupportedOperationException("can't resolve declaration to callable: " + fd); @@ -2076,7 +2086,7 @@ public class ExpressionCodegen extends JetVisitor { } } - void generateTypeInfo(JetType jetType) { + public void generateTypeInfo(JetType jetType) { String knownTypeInfo = typeMapper.isKnownTypeInfo(jetType); if(knownTypeInfo != null) { v.getstatic("jet/typeinfo/TypeInfo", knownTypeInfo, "Ljet/typeinfo/TypeInfo;"); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 2b6513a7a0f..a78333d30c9 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -2,7 +2,6 @@ package org.jetbrains.jet.codegen; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; -import jet.Function1; import jet.JetObject; import jet.typeinfo.TypeInfo; import jet.typeinfo.TypeInfoProjection; @@ -58,6 +57,7 @@ public class JetTypeMapper { private final HashMap knowTypes = new HashMap(); public static final Type TYPE_FUNCTION1 = Type.getObjectType("jet/Function1"); + public static final Type TYPE_ITERATOR = Type.getObjectType("jet/Iterator"); public JetTypeMapper(JetStandardLibrary standardLibrary, BindingContext bindingContext) { this.standardLibrary = standardLibrary; @@ -464,17 +464,16 @@ public class JetTypeMapper { } - private Method mapSignature(JetNamedFunction f, List valueParameterTypes, OwnerKind kind) { - final JetTypeReference receiverTypeRef = f.getReceiverTypeRef(); - final JetType receiverType = receiverTypeRef == null ? null : bindingContext.get(BindingContext.TYPE, receiverTypeRef); - final List parameters = f.getValueParameters(); + private Method mapSignature(FunctionDescriptor f, List valueParameterTypes, OwnerKind kind) { + final ReceiverDescriptor receiverTypeRef = f.getReceiver(); + final JetType receiverType = receiverTypeRef == ReceiverDescriptor.NO_RECEIVER ? null : receiverTypeRef.getType(); + final List parameters = f.getValueParameters(); List parameterTypes = new ArrayList(); if (receiverType != null) { parameterTypes.add(mapType(receiverType)); } - FunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, f); if(kind == OwnerKind.TRAIT_IMPL) { - ClassDescriptor containingDeclaration = (ClassDescriptor) functionDescriptor.getContainingDeclaration(); + ClassDescriptor containingDeclaration = (ClassDescriptor) f.getContainingDeclaration(); JetType jetType = TraitImplBodyCodegen.getSuperClass(containingDeclaration, bindingContext); Type type = mapType(jetType); if(type.getInternalName().equals("java/lang/Object")) { @@ -484,24 +483,15 @@ public class JetTypeMapper { valueParameterTypes.add(type); parameterTypes.add(type); } - for (JetParameter parameter : parameters) { - final Type type = mapType(bindingContext.get(BindingContext.TYPE, parameter.getTypeReference())); + for (ValueParameterDescriptor parameter : parameters) { + final Type type = mapType(parameter.getOutType()); valueParameterTypes.add(type); parameterTypes.add(type); } for (int n = f.getTypeParameters().size(); n > 0; n--) { parameterTypes.add(TYPE_TYPEINFO); } - final JetTypeReference returnTypeRef = f.getReturnTypeRef(); - Type returnType; - if (returnTypeRef == null) { - assert functionDescriptor != null; - final JetType type = functionDescriptor.getReturnType(); - returnType = mapReturnType(type); - } - else { - returnType = mapReturnType(bindingContext.get(BindingContext.TYPE, returnTypeRef)); - } + Type returnType = mapReturnType(f.getReturnType()); return new Method(f.getName(), returnType, parameterTypes.toArray(new Type[parameterTypes.size()])); } @@ -515,9 +505,13 @@ public class JetTypeMapper { JetNamedFunction f = (JetNamedFunction) declaration; final FunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, f); assert functionDescriptor != null; + return mapToCallableMethod(functionDescriptor, kind); + } + + public CallableMethod mapToCallableMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) { final DeclarationDescriptor functionParent = functionDescriptor.getContainingDeclaration(); final List valueParameterTypes = new ArrayList(); - Method descriptor = mapSignature(f, valueParameterTypes, kind); + Method descriptor = mapSignature(functionDescriptor.getOriginal(), valueParameterTypes, kind); String owner; int invokeOpcode; boolean needsReceiver; @@ -525,7 +519,7 @@ public class JetTypeMapper { if (functionParent instanceof NamespaceDescriptor) { owner = NamespaceCodegen.getJVMClassName(DescriptorRenderer.getFQName(functionParent)); invokeOpcode = Opcodes.INVOKESTATIC; - needsReceiver = f.getReceiverTypeRef() != null; + needsReceiver = functionDescriptor.getReceiver() != ReceiverDescriptor.NO_RECEIVER; } else if (functionParent instanceof ClassDescriptor) { ClassDescriptor containingClass = (ClassDescriptor) functionParent; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java index 7a7c280f8e1..f60fc9804cc 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java @@ -197,6 +197,9 @@ public abstract class StackValue { if (type.getSort() == Type.BOOLEAN) { v.checkcast(JetTypeMapper.JL_BOOLEAN_TYPE); } + else if (type.getSort() == Type.CHAR) { + v.checkcast(JetTypeMapper.JL_CHAR_TYPE); + } else { v.checkcast(JetTypeMapper.JL_NUMBER_TYPE); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIterator.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIterator.java new file mode 100644 index 00000000000..c61130a7b15 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIterator.java @@ -0,0 +1,65 @@ +package org.jetbrains.jet.codegen.intrinsics; + +import com.intellij.psi.PsiElement; +import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.JetTypeMapper; +import org.jetbrains.jet.codegen.StackValue; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.psi.JetCallExpression; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.types.JetStandardLibrary; +import org.jetbrains.jet.lang.types.JetType; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.InstructionAdapter; + +import java.util.List; + +/** + * @author alex.tkachman + */ +public class ArrayIterator implements IntrinsicMethod { + @Override + public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { + receiver.put(JetTypeMapper.TYPE_OBJECT, v); + JetCallExpression call = (JetCallExpression) element; + FunctionDescriptor funDescriptor = (FunctionDescriptor) codegen.getBindingContext().get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) call.getCalleeExpression()); + ClassDescriptor containingDeclaration = (ClassDescriptor) funDescriptor.getContainingDeclaration().getOriginal(); + JetStandardLibrary standardLibrary = codegen.getState().getStandardLibrary(); + if(containingDeclaration.equals(standardLibrary.getArray())) { + codegen.generateTypeInfo(funDescriptor.getReturnType().getArguments().get(0).getType()); + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([Ljava/lang/Object;Ljet/typeinfo/TypeInfo;)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getByteArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([B)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getShortArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([S)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getIntArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([I)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getLongArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([J)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getFloatArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([F)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getDoubleArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([D)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getCharArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([C)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getBooleanArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([Z)Ljet/Iterator;"); + } + else { + throw new UnsupportedOperationException(containingDeclaration.toString()); + } + return StackValue.onStack(JetTypeMapper.TYPE_ITERATOR); + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java index ce4c0e29b46..3c2eee1cadc 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java @@ -34,6 +34,7 @@ public class IntrinsicMethods { private final Project myProject; private final JetStandardLibrary myStdLib; private final Map myMethods = new HashMap(); + private static final IntrinsicMethod ARRAY_ITERATOR = new ArrayIterator(); public IntrinsicMethods(Project project, JetStandardLibrary stdlib) { myProject = project; @@ -87,6 +88,16 @@ public class IntrinsicMethods { declareIntrinsicProperty("DoubleArray", "size", ARRAY_SIZE); declareIntrinsicProperty("CharArray", "size", ARRAY_SIZE); declareIntrinsicProperty("BooleanArray", "size", ARRAY_SIZE); + + declareOverload(myStdLib.getArray().getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); + declareOverload(myStdLib.getByteArrayClass().getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); + declareOverload(myStdLib.getShortArrayClass().getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); + declareOverload(myStdLib.getIntArrayClass().getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); + declareOverload(myStdLib.getLongArrayClass().getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); + declareOverload(myStdLib.getFloatArrayClass().getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); + declareOverload(myStdLib.getDoubleArrayClass().getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); + declareOverload(myStdLib.getCharArrayClass().getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); + declareOverload(myStdLib.getBooleanArrayClass().getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); } private void declareIntrinsicStringMethods() { diff --git a/compiler/frontend/src/jet/Library.jet b/compiler/frontend/src/jet/Library.jet index f11575b99d3..1c97f0374d4 100644 --- a/compiler/frontend/src/jet/Library.jet +++ b/compiler/frontend/src/jet/Library.jet @@ -42,7 +42,7 @@ fun Any?.toString() : String// = this === other trait Iterator { fun next() : T - abstract fun hasNext() : Boolean + fun hasNext() : Boolean } trait Iterable { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java index 2036d25cafb..6029d19c358 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java @@ -312,8 +312,7 @@ public class JetStandardLibrary { @NotNull public JetType getArrayType(@NotNull JetType argument) { - Variance variance = Variance.INVARIANT; - return getArrayType(variance, argument); + return getArrayType(Variance.INVARIANT, argument); } @NotNull diff --git a/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java b/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java index dcd5e4d9783..292fdbd2518 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java @@ -58,4 +58,32 @@ public class ArrayGenTest extends CodegenTestCase { System.out.println(invoke.getClass()); assertTrue(invoke instanceof Integer); } + + public void testIterator () throws Exception { + loadText("fun box() { val x = Array(5, { it } ).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } + + public void testPrimitiveIterator () throws Exception { + loadText("fun box() { val x = ByteArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } + + public void testLongIterator () throws Exception { + loadText("fun box() { val x = LongArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } + + public void testCharIterator () throws Exception { + loadText("fun box() { val x = CharArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } } diff --git a/stdlib/src/jet/arrays/ArrayIterator.java b/stdlib/src/jet/arrays/ArrayIterator.java new file mode 100644 index 00000000000..3bbfac045f3 --- /dev/null +++ b/stdlib/src/jet/arrays/ArrayIterator.java @@ -0,0 +1,274 @@ +package jet.arrays; + +import jet.Iterator; +import jet.typeinfo.TypeInfo; +import jet.typeinfo.TypeInfoProjection; + +import java.lang.reflect.GenericArrayType; +import java.util.Arrays; + +/** + * @author alex.tkachman + */ +public abstract class ArrayIterator implements Iterator { + private final int size; + protected int index; + + protected ArrayIterator(int size) { + this.size = size; + } + + @Override + public boolean hasNext() { + return index < size; + } + + private static class GenericIterator extends ArrayIterator { + private final T[] array; + private final TypeInfo elementTypeInfo; + + private GenericIterator(T[] array, TypeInfo elementTypeInfo) { + super(array.length); + this.array = array; + this.elementTypeInfo = elementTypeInfo; + } + + @Override + public T next() { + return array[index++]; + } + + @Override + public TypeInfo getTypeInfo() { + return TypeInfo.getTypeInfo(GenericIterator.class, false, null, new TypeInfoProjection[] {(TypeInfoProjection) elementTypeInfo}); + } + } + + public static Iterator iterator(T[] array, TypeInfo elementTypeInfo) { + return new GenericIterator(array, elementTypeInfo); + } + + private static class ByteIterator extends ArrayIterator { + private final byte[] array; + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(ByteIterator.class, false); + + private ByteIterator(byte[] array) { + super(array.length); + this.array = array; + } + + @Override + public Byte next() { + return array[index++]; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + } + + public static Iterator iterator(byte[] array) { + return new ByteIterator(array); + } + + private static class ShortIterator extends ArrayIterator { + private final short[] array; + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(ShortIterator.class, false); + + private ShortIterator(short[] array) { + super(array.length); + this.array = array; + } + + @Override + public Short next() { + return array[index++]; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + } + + public static Iterator iterator(short[] array) { + return new ShortIterator(array); + } + + private static class IntegerIterator extends ArrayIterator { + private final int[] array; + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(IntegerIterator.class, false); + + private IntegerIterator(int[] array) { + super(array.length); + this.array = array; + } + + @Override + public Integer next() { + return array[index++]; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + } + + public static Iterator iterator(int[] array) { + return new IntegerIterator(array); + } + + private static class LongIterator extends ArrayIterator { + private final long[] array; + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(LongIterator.class, false); + + private LongIterator(long[] array) { + super(array.length); + this.array = array; + } + + @Override + public Long next() { + return array[index++]; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + } + + public static Iterator iterator(long[] array) { + return new LongIterator(array); + } + + private static class FloatIterator extends ArrayIterator { + private final float[] array; + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(FloatIterator.class, false); + + private FloatIterator(float[] array) { + super(array.length); + this.array = array; + } + + @Override + public Float next() { + return array[index++]; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + } + + public static Iterator iterator(float[] array) { + return new FloatIterator(array); + } + + private static class DoubleIterator extends ArrayIterator { + private final double[] array; + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(DoubleIterator.class, false); + + private DoubleIterator(double[] array) { + super(array.length); + this.array = array; + } + + @Override + public Double next() { + return array[index++]; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + } + + public static Iterator iterator(double[] array) { + return new DoubleIterator(array); + } + + private static class CharacterIterator extends ArrayIterator { + private final char[] array; + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(CharacterIterator.class, false); + + private CharacterIterator(char[] array) { + super(array.length); + this.array = array; + } + + @Override + public Character next() { + return array[index++]; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + } + + public static Iterator iterator(char[] array) { + return new CharacterIterator(array); + } + + private static class BooleanIterator extends ArrayIterator { + private final boolean[] array; + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(BooleanIterator.class, false); + + private BooleanIterator(boolean[] array) { + super(array.length); + this.array = array; + } + + @Override + public Boolean next() { + return array[index++]; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + } + + public static Iterator iterator(boolean[] array) { + return new BooleanIterator(array); + } + + public static void main(String[] args) { + String[] strings = {"Byte", "byte", "Short", "short", "Integer", "int", "Long", "long", "Float", "float", "Double", "double", "Character", "char", "Boolean", "boolean"}; + for(int i = 0; i != strings.length; i += 2) { + String boxed = strings[i]; + String unboxed = strings[i+1]; + System.out.println(" private static class " + boxed + "Iterator extends ArrayIterator<" + boxed + "> {\n" + + " private final " + unboxed + "[] array;\n" + + " private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(" + boxed + "Iterator.class, false);\n" + + "\n" + + " private " + boxed + "Iterator(" + unboxed + "[] array) {\n" + + " super(array.length);\n" + + " this.array = array;\n" + + " }\n" + + "\n" + + " @Override\n" + + " public " + boxed + " next() {\n" + + " return array[index++];\n" + + " }\n" + + "\n" + + " @Override\n" + + " public TypeInfo getTypeInfo() {\n" + + " return typeInfo;\n" + + " }\n" + + " }\n" + + "\n" + + " public static Iterator<" + boxed + "> iterator(" + unboxed + "[] array) {\n" + + " return new " + boxed + "Iterator(array);\n" + + " }\n" + + ""); + } + } +} From e94087f41eb67d17bb62dca4fef32cbfd9954260 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Sat, 8 Oct 2011 16:26:49 +0200 Subject: [PATCH 04/14] array.indices --- .../jetbrains/jet/codegen/JetTypeMapper.java | 1 + .../jet/codegen/intrinsics/ArrayIndices.java | 21 +++++ .../codegen/intrinsics/IntrinsicMethods.java | 35 ++++++--- compiler/frontend/src/jet/Library.jet | 78 ++++++++++++------- .../jetbrains/jet/codegen/ArrayGenTest.java | 14 ++++ .../jet/codegen/NamespaceGenTest.java | 4 +- stdlib/src/jet/IntRange.java | 65 +++++++++++++--- stdlib/src/jet/LongRange.java | 75 ++++++++++++++++++ 8 files changed, 246 insertions(+), 47 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIndices.java create mode 100644 stdlib/src/jet/LongRange.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index a78333d30c9..9cf778f138a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -58,6 +58,7 @@ public class JetTypeMapper { private final HashMap knowTypes = new HashMap(); public static final Type TYPE_FUNCTION1 = Type.getObjectType("jet/Function1"); public static final Type TYPE_ITERATOR = Type.getObjectType("jet/Iterator"); + public static final Type TYPE_INT_RANGE = Type.getObjectType("jet/IntRange"); public JetTypeMapper(JetStandardLibrary standardLibrary, BindingContext bindingContext) { this.standardLibrary = standardLibrary; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIndices.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIndices.java new file mode 100644 index 00000000000..4049e238e43 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIndices.java @@ -0,0 +1,21 @@ +package org.jetbrains.jet.codegen.intrinsics; + +import com.intellij.psi.PsiElement; +import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.JetTypeMapper; +import org.jetbrains.jet.codegen.StackValue; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.InstructionAdapter; + +import java.util.List; + +public class ArrayIndices implements IntrinsicMethod { + @Override + public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { + receiver.put(JetTypeMapper.TYPE_OBJECT, v); + v.arraylength(); + v.invokestatic("jet/IntRange", "count", "(I)Ljet/IntRange;"); + return StackValue.onStack(JetTypeMapper.TYPE_INT_RANGE); + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java index 3c2eee1cadc..b1efba96116 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java @@ -29,7 +29,8 @@ public class IntrinsicMethods { private static final IntrinsicMethod DEC = new Increment(-1); private static final List PRIMITIVE_NUMBER_TYPES = ImmutableList.of("Boolean", "Byte", "Char", "Short", "Int", "Float", "Long", "Double"); - public static final ArraySize ARRAY_SIZE = new ArraySize(); + public static final IntrinsicMethod ARRAY_SIZE = new ArraySize(); + public static final IntrinsicMethod ARRAY_INDICES = new ArrayIndices(); private final Project myProject; private final JetStandardLibrary myStdLib; @@ -89,15 +90,29 @@ public class IntrinsicMethods { declareIntrinsicProperty("CharArray", "size", ARRAY_SIZE); declareIntrinsicProperty("BooleanArray", "size", ARRAY_SIZE); - declareOverload(myStdLib.getArray().getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); - declareOverload(myStdLib.getByteArrayClass().getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); - declareOverload(myStdLib.getShortArrayClass().getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); - declareOverload(myStdLib.getIntArrayClass().getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); - declareOverload(myStdLib.getLongArrayClass().getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); - declareOverload(myStdLib.getFloatArrayClass().getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); - declareOverload(myStdLib.getDoubleArrayClass().getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); - declareOverload(myStdLib.getCharArrayClass().getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); - declareOverload(myStdLib.getBooleanArrayClass().getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); + declareIntrinsicProperty("Array", "indices", ARRAY_INDICES); + declareIntrinsicProperty("ByteArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("ShortArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("IntArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("LongArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("FloatArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("DoubleArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("CharArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("BooleanArray", "indices", ARRAY_INDICES); + + declareIterator(myStdLib.getArray()); + declareIterator(myStdLib.getByteArrayClass()); + declareIterator(myStdLib.getShortArrayClass()); + declareIterator(myStdLib.getIntArrayClass()); + declareIterator(myStdLib.getLongArrayClass()); + declareIterator(myStdLib.getFloatArrayClass()); + declareIterator(myStdLib.getDoubleArrayClass()); + declareIterator(myStdLib.getCharArrayClass()); + declareIterator(myStdLib.getBooleanArrayClass()); + } + + private void declareIterator(ClassDescriptor classDescriptor) { + declareOverload(classDescriptor.getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); } private void declareIntrinsicStringMethods() { diff --git a/compiler/frontend/src/jet/Library.jet b/compiler/frontend/src/jet/Library.jet index 1c97f0374d4..7a763882893 100644 --- a/compiler/frontend/src/jet/Library.jet +++ b/compiler/frontend/src/jet/Library.jet @@ -54,6 +54,8 @@ class Array(val size : Int, init : fun(Int) : T = null ) { fun set(index : Int, value : T) : Unit fun iterator() : Iterator + + val indices : IntRange } class ByteArray(val size : Int) { @@ -61,6 +63,8 @@ class ByteArray(val size : Int) { fun set(index : Int, value : Byte) : Unit fun iterator() : Iterator + + val indices : IntRange } class ShortArray(val size : Int) { @@ -68,6 +72,8 @@ class ShortArray(val size : Int) { fun set(index : Int, value : Short) : Unit fun iterator() : Iterator + + val indices : IntRange } class IntArray(val size : Int) { @@ -75,6 +81,8 @@ class IntArray(val size : Int) { fun set(index : Int, value : Int) : Unit fun iterator() : Iterator + + val indices : IntRange } class LongArray(val size : Int) { @@ -82,6 +90,8 @@ class LongArray(val size : Int) { fun set(index : Int, value : Long) : Unit fun iterator() : Iterator + + val indices : IntRange } class FloatArray(val size : Int) { @@ -89,6 +99,8 @@ class FloatArray(val size : Int) { fun set(index : Int, value : Float) : Unit fun iterator() : Iterator + + val indices : IntRange } class DoubleArray(val size : Int) { @@ -96,6 +108,8 @@ class DoubleArray(val size : Int) { fun set(index : Int, value : Double) : Unit fun iterator() : Iterator + + val indices : IntRange } class CharArray(val size : Int) { @@ -103,6 +117,8 @@ class CharArray(val size : Int) { fun set(index : Int, value : Char) : Unit fun iterator() : Iterator + + val indices : IntRange } class BooleanArray(val size : Int) { @@ -110,6 +126,8 @@ class BooleanArray(val size : Int) { fun set(index : Int, value : Boolean) : Unit fun iterator() : Iterator + + val indices : IntRange } trait Comparable { @@ -152,8 +170,16 @@ trait Range> { fun contains(item : T) : Boolean } -class IntRange>(val start : Int, val end : Int) : Range, Iterable { +class IntRange(val start : Int, val excludedEnd : Int) : Range, Iterable { + fun iterator () : Iterator + fun contains (elem: Int) : Boolean +} + +class LongRange(val start : Long, val end : Long) : Range, Iterable { + fun iterator () : Iterator + + fun contains (elem: Long) : Boolean } abstract class Number : Hashable { @@ -349,11 +375,11 @@ class Long : Number, Comparable { fun rangeTo(other : Double) : Range fun rangeTo(other : Float) : Range - fun rangeTo(other : Long) : IntRange - fun rangeTo(other : Int) : IntRange - fun rangeTo(other : Short) : IntRange - fun rangeTo(other : Byte) : IntRange - fun rangeTo(other : Char) : IntRange + fun rangeTo(other : Long) : LongRange + fun rangeTo(other : Int) : LongRange + fun rangeTo(other : Short) : LongRange + fun rangeTo(other : Byte) : LongRange + fun rangeTo(other : Char) : LongRange fun inc() : Long fun dec() : Long @@ -420,11 +446,11 @@ class Int : Number, Comparable { fun rangeTo(other : Double) : Range fun rangeTo(other : Float) : Range - fun rangeTo(other : Long) : IntRange - fun rangeTo(other : Int) : IntRange - fun rangeTo(other : Short) : IntRange - fun rangeTo(other : Byte) : IntRange - fun rangeTo(other : Char) : IntRange + fun rangeTo(other : Long) : LongRange + fun rangeTo(other : Int) : IntRange + fun rangeTo(other : Short) : IntRange + fun rangeTo(other : Byte) : IntRange + fun rangeTo(other : Char) : IntRange fun inc() : Int fun dec() : Int @@ -491,11 +517,11 @@ class Char : Number, Comparable { fun rangeTo(other : Double) : Range fun rangeTo(other : Float) : Range - fun rangeTo(other : Long) : IntRange - fun rangeTo(other : Int) : IntRange - fun rangeTo(other : Short) : IntRange - fun rangeTo(other : Byte) : IntRange - fun rangeTo(other : Char) : IntRange + fun rangeTo(other : Long) : LongRange + fun rangeTo(other : Int) : IntRange + fun rangeTo(other : Short) : IntRange + fun rangeTo(other : Byte) : IntRange + fun rangeTo(other : Char) : IntRange fun inc() : Char fun dec() : Char @@ -554,11 +580,11 @@ class Short : Number, Comparable { fun rangeTo(other : Double) : Range fun rangeTo(other : Float) : Range - fun rangeTo(other : Long) : IntRange - fun rangeTo(other : Int) : IntRange - fun rangeTo(other : Short) : IntRange - fun rangeTo(other : Byte) : IntRange - fun rangeTo(other : Char) : IntRange + fun rangeTo(other : Long) : LongRange + fun rangeTo(other : Int) : IntRange + fun rangeTo(other : Short) : IntRange + fun rangeTo(other : Byte) : IntRange + fun rangeTo(other : Char) : IntRange fun inc() : Short fun dec() : Short @@ -617,11 +643,11 @@ class Byte : Number, Comparable { fun rangeTo(other : Double) : Range fun rangeTo(other : Float) : Range - fun rangeTo(other : Long) : IntRange - fun rangeTo(other : Int) : IntRange - fun rangeTo(other : Short) : IntRange - fun rangeTo(other : Byte) : IntRange - fun rangeTo(other : Char) : IntRange + fun rangeTo(other : Long) : LongRange + fun rangeTo(other : Int) : IntRange + fun rangeTo(other : Short) : IntRange + fun rangeTo(other : Byte) : IntRange + fun rangeTo(other : Char) : IntRange fun inc() : Byte fun dec() : Byte diff --git a/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java b/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java index 292fdbd2518..a7aa2572f54 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java @@ -86,4 +86,18 @@ public class ArrayGenTest extends CodegenTestCase { Method foo = generateFunction(); foo.invoke(null); } + + public void testArrayIndices () throws Exception { + loadText("fun box() { val x = Array(5, {it}).indices.iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } + + public void testCharIndices () throws Exception { + loadText("fun box() { val x = CharArray(5).indices.iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } } diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index a1f2940a78e..4420f4c7321 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -433,8 +433,8 @@ public class NamespaceGenTest extends CodegenTestCase { final Method main = generateFunction(); IntRange result = (IntRange) main.invoke(null); assertTrue(result.contains(1)); - assertTrue(result.contains(10)); - assertFalse(result.contains(11)); + assertTrue(result.contains(9)); + assertFalse(result.contains(10)); } public void testSubstituteJavaMethodTypeParameters() throws Exception { diff --git a/stdlib/src/jet/IntRange.java b/stdlib/src/jet/IntRange.java index dc538cddc4b..67dd7c3ed52 100644 --- a/stdlib/src/jet/IntRange.java +++ b/stdlib/src/jet/IntRange.java @@ -1,28 +1,75 @@ package jet; -public class IntRange implements Range { +import jet.typeinfo.TypeInfo; + +public final class IntRange implements Range, Iterable, JetObject { + private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(IntRange.class, false); + private final int startValue; - private final int endValue; + private final int excludedEndValue; public IntRange(int startValue, int endValue) { this.startValue = startValue; - this.endValue = endValue; + this.excludedEndValue = endValue; } @Override public boolean contains(Integer item) { if (item == null) return false; - if (startValue <= endValue) { - return item >= startValue && item <= endValue; + if (startValue < excludedEndValue) { + return item >= startValue && item < excludedEndValue; } - return item <= startValue && item >= endValue; + return item <= startValue && item > excludedEndValue; } - public int getStartValue() { + public int getStart() { return startValue; } - public int getEndValue() { - return endValue; + public int getEnd() { + return excludedEndValue; + } + + @Override + public Iterator iterator() { + return new MyIterator(startValue, excludedEndValue); + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + + public static IntRange count(int length) { + return new IntRange(0, length); + } + + private static class MyIterator implements Iterator { + private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(MyIterator.class, false); + private final int lastValue; + + private int cur; + private boolean reversed; + + public MyIterator(int startValue, int endValue) { + reversed = endValue <= startValue; + this.lastValue = reversed ? startValue : endValue-1; + cur = reversed ? endValue-1 : startValue; + } + + @Override + public boolean hasNext() { + return reversed ? cur >= lastValue : cur <= lastValue; + } + + @Override + public Integer next() { + return reversed ? cur-- : cur++; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } } } diff --git a/stdlib/src/jet/LongRange.java b/stdlib/src/jet/LongRange.java new file mode 100644 index 00000000000..05dff1bacba --- /dev/null +++ b/stdlib/src/jet/LongRange.java @@ -0,0 +1,75 @@ +package jet; + +import jet.typeinfo.TypeInfo; + +public final class LongRange implements Range, Iterable, JetObject { + private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(IntRange.class, false); + + private final long startValue; + private final long excludedEndValue; + + public LongRange(long startValue, long endValue) { + this.startValue = startValue; + this.excludedEndValue = endValue; + } + + @Override + public boolean contains(Long item) { + if (item == null) return false; + if (startValue < excludedEndValue) { + return item >= startValue && item < excludedEndValue; + } + return item <= startValue && item > excludedEndValue; + } + + public long getStart() { + return startValue; + } + + public long getEnd() { + return excludedEndValue; + } + + @Override + public Iterator iterator() { + return new MyIterator(startValue, excludedEndValue); + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + + public static IntRange count(int length) { + return new IntRange(0, length); + } + + private static class MyIterator implements Iterator { + private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(MyIterator.class, false); + private final long lastValue; + + private long cur; + private boolean reversed; + + public MyIterator(long startValue, long endValue) { + reversed = endValue <= startValue; + this.lastValue = reversed ? startValue : endValue-1; + cur = reversed ? endValue-1 : startValue; + } + + @Override + public boolean hasNext() { + return reversed ? cur >= lastValue : cur <= lastValue; + } + + @Override + public Long next() { + return reversed ? cur-- : cur++; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + } +} From 7bf066c4bfa0f5ed0ef03be6a2647d3d3e9ce303 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Sat, 8 Oct 2011 17:07:08 +0200 Subject: [PATCH 05/14] IntRange allows empty and reversed ranges --- .../jet/codegen/ExpressionCodegen.java | 4 +- .../jet/codegen/intrinsics/RangeTo.java | 10 +-- compiler/frontend/src/jet/Library.jet | 16 ++++- .../jet/codegen/NamespaceGenTest.java | 4 +- stdlib/src/jet/IntRange.java | 62 +++++++++++++------ stdlib/src/jet/LongRange.java | 62 +++++++++++++------ 6 files changed, 106 insertions(+), 52 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 6caf932976d..ea7afc3dd7b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -217,7 +217,7 @@ public class ExpressionCodegen extends JetVisitor { else { assert expressionType != null; final DeclarationDescriptor descriptor = expressionType.getConstructor().getDeclarationDescriptor(); - if (isClass(descriptor, "IntRange")) { // TODO IntRange subclasses + if (isClass(descriptor, "IntRange")) { // TODO IntRange subclasses (now IntRange is final) new ForInRangeLoopGenerator(expression, loopRangeType).invoke(); return StackValue.none(); } @@ -2297,7 +2297,7 @@ public class ExpressionCodegen extends JetVisitor { JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, rangeExpression); assert jetType != null; final DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); - if (isClass(descriptor, "IntRange")) { // TODO IntRange subclasses + if (isClass(descriptor, "IntRange")) { return true; } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/RangeTo.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/RangeTo.java index 79953a13b0f..86850d21051 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/RangeTo.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/RangeTo.java @@ -16,21 +16,15 @@ import java.util.List; * @author yole */ public class RangeTo implements IntrinsicMethod { - private static final String INT_RANGE_CONSTRUCTOR_DESCRIPTOR = "(II)V"; - private static final Type INT_RANGE_TYPE = Type.getType(IntRange.class); - private static final String CLASS_INT_RANGE = "jet/IntRange"; - @Override public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { JetBinaryExpression expression = (JetBinaryExpression) element; final Type leftType = codegen.expressionType(expression.getLeft()); if (JetTypeMapper.isIntPrimitive(leftType)) { - v.anew(INT_RANGE_TYPE); - v.dup(); codegen.gen(expression.getLeft(), Type.INT_TYPE); codegen.gen(expression.getRight(), Type.INT_TYPE); - v.invokespecial(CLASS_INT_RANGE, "", INT_RANGE_CONSTRUCTOR_DESCRIPTOR); - return StackValue.onStack(INT_RANGE_TYPE); + v.invokestatic("jet/IntRange", "rangeTo", "(II)Ljet/IntRange;"); + return StackValue.onStack(JetTypeMapper.TYPE_INT_RANGE); } else { throw new UnsupportedOperationException("ranges are only supported for int objects"); diff --git a/compiler/frontend/src/jet/Library.jet b/compiler/frontend/src/jet/Library.jet index 7a763882893..0a57bbf4c91 100644 --- a/compiler/frontend/src/jet/Library.jet +++ b/compiler/frontend/src/jet/Library.jet @@ -170,16 +170,28 @@ trait Range> { fun contains(item : T) : Boolean } -class IntRange(val start : Int, val excludedEnd : Int) : Range, Iterable { +class IntRange(val start : Int, size : Int, reversed : Boolean = false) : Range, Iterable { fun iterator () : Iterator fun contains (elem: Int) : Boolean + + val size : Int + + val end : Int + + val reversed : Boolean } -class LongRange(val start : Long, val end : Long) : Range, Iterable { +class LongRange(val start : Long, size : Long, reversed : Boolean = false) : Range, Iterable { fun iterator () : Iterator fun contains (elem: Long) : Boolean + + val size : Long + + val end : Long + + val reversed : Boolean } abstract class Number : Hashable { diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index 4420f4c7321..a1f2940a78e 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -433,8 +433,8 @@ public class NamespaceGenTest extends CodegenTestCase { final Method main = generateFunction(); IntRange result = (IntRange) main.invoke(null); assertTrue(result.contains(1)); - assertTrue(result.contains(9)); - assertFalse(result.contains(10)); + assertTrue(result.contains(10)); + assertFalse(result.contains(11)); } public void testSubstituteJavaMethodTypeParameters() throws Exception { diff --git a/stdlib/src/jet/IntRange.java b/stdlib/src/jet/IntRange.java index 67dd7c3ed52..abeb2a0f696 100644 --- a/stdlib/src/jet/IntRange.java +++ b/stdlib/src/jet/IntRange.java @@ -5,34 +5,42 @@ import jet.typeinfo.TypeInfo; public final class IntRange implements Range, Iterable, JetObject { private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(IntRange.class, false); - private final int startValue; - private final int excludedEndValue; + private final int start; + private final int count; - public IntRange(int startValue, int endValue) { - this.startValue = startValue; - this.excludedEndValue = endValue; + public IntRange(int startValue, int count) { + this.start = startValue; + this.count = count; + } + + public IntRange(int startValue, int count, boolean reversed) { + this(startValue, reversed ? -count : count); } @Override public boolean contains(Integer item) { if (item == null) return false; - if (startValue < excludedEndValue) { - return item >= startValue && item < excludedEndValue; + if (count >= 0) { + return item >= start && item < start + count; } - return item <= startValue && item > excludedEndValue; + return item <= start && item > start + count; } public int getStart() { - return startValue; + return start; } public int getEnd() { - return excludedEndValue; + return start+count-1; + } + + public int getSize() { + return count < 0 ? -count : count; } @Override public Iterator iterator() { - return new MyIterator(startValue, excludedEndValue); + return new MyIterator(start, count); } @Override @@ -44,27 +52,43 @@ public final class IntRange implements Range, Iterable, JetObj return new IntRange(0, length); } + public static IntRange rangeTo(int from, int to) { + if(from > to) { + return new IntRange(to, from-to+1, true); + } + else { + return new IntRange(from, to-from+1); + } + } + private static class MyIterator implements Iterator { private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(MyIterator.class, false); - private final int lastValue; private int cur; - private boolean reversed; + private int count; - public MyIterator(int startValue, int endValue) { - reversed = endValue <= startValue; - this.lastValue = reversed ? startValue : endValue-1; - cur = reversed ? endValue-1 : startValue; + private final boolean reversed; + + public MyIterator(int startValue, int count) { + cur = startValue; + reversed = count < 0; + this.count = reversed ? -count : count; } @Override public boolean hasNext() { - return reversed ? cur >= lastValue : cur <= lastValue; + return count > 0; } @Override public Integer next() { - return reversed ? cur-- : cur++; + count--; + if(reversed) { + return cur--; + } + else { + return cur++; + } } @Override diff --git a/stdlib/src/jet/LongRange.java b/stdlib/src/jet/LongRange.java index 05dff1bacba..7932f7d0b5d 100644 --- a/stdlib/src/jet/LongRange.java +++ b/stdlib/src/jet/LongRange.java @@ -5,34 +5,42 @@ import jet.typeinfo.TypeInfo; public final class LongRange implements Range, Iterable, JetObject { private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(IntRange.class, false); - private final long startValue; - private final long excludedEndValue; + private final long start; + private final long count; - public LongRange(long startValue, long endValue) { - this.startValue = startValue; - this.excludedEndValue = endValue; + public LongRange(long startValue, long count) { + this.start = startValue; + this.count = count; + } + + public LongRange(long startValue, long count, boolean reversed) { + this(startValue, reversed ? -count : count); } @Override public boolean contains(Long item) { if (item == null) return false; - if (startValue < excludedEndValue) { - return item >= startValue && item < excludedEndValue; + if (count >= 0) { + return item >= start && item < start + count; } - return item <= startValue && item > excludedEndValue; + return item <= start && item > start + count; } public long getStart() { - return startValue; + return start; } public long getEnd() { - return excludedEndValue; + return start+count-1; + } + + public long getSize() { + return count < 0 ? -count : count; } @Override public Iterator iterator() { - return new MyIterator(startValue, excludedEndValue); + return new MyIterator(start, count); } @Override @@ -44,27 +52,43 @@ public final class LongRange implements Range, Iterable, JetObject { return new IntRange(0, length); } + public static IntRange rangeTo(int from, int to) { + if(from > to) { + return new IntRange(to, from-to+1, true); + } + else { + return new IntRange(from, to-from+1); + } + } + private static class MyIterator implements Iterator { private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(MyIterator.class, false); - private final long lastValue; private long cur; - private boolean reversed; + private long count; - public MyIterator(long startValue, long endValue) { - reversed = endValue <= startValue; - this.lastValue = reversed ? startValue : endValue-1; - cur = reversed ? endValue-1 : startValue; + private final boolean reversed; + + public MyIterator(long startValue, long count) { + cur = startValue; + reversed = count < 0; + this.count = reversed ? -count : count; } @Override public boolean hasNext() { - return reversed ? cur >= lastValue : cur <= lastValue; + return count > 0; } @Override public Long next() { - return reversed ? cur-- : cur++; + count--; + if(reversed) { + return cur--; + } + else { + return cur++; + } } @Override From 9f53486922e32415108d365416c2071e05e98ad7 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Sun, 9 Oct 2011 10:33:23 +0200 Subject: [PATCH 06/14] failing test for kt343 --- idea/testData/codegen/regressions/kt343.jet | 16 ++++++++++++++++ .../org/jetbrains/jet/codegen/ClassGenTest.java | 5 +++++ 2 files changed, 21 insertions(+) create mode 100644 idea/testData/codegen/regressions/kt343.jet diff --git a/idea/testData/codegen/regressions/kt343.jet b/idea/testData/codegen/regressions/kt343.jet new file mode 100644 index 00000000000..d71ccc41a01 --- /dev/null +++ b/idea/testData/codegen/regressions/kt343.jet @@ -0,0 +1,16 @@ +import java.util.ArrayList + +fun box(): String { + val list = ArrayList() + val foo : fun() : Unit = { + list.add(2) //first exception + } + foo() + +// val bar = { +// val x = 1 //second exception +// } +// bar() + + return if (list.get(0) == 2) "OK" else "fail" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java index 17e5d4f9252..72a131c61c6 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -185,4 +185,9 @@ public class ClassGenTest extends CodegenTestCase { assertEquals(method.getReturnType().getName(), "java.lang.Object"); System.out.println(generateToText()); } + + public void testKt343 () throws Exception { + blackBoxFile("regressions/kt343.jet"); + System.out.println(generateToText()); + } } From a59d5d72a60772a7e0d718ae5ecfeda292ef4c6b Mon Sep 17 00:00:00 2001 From: svtk Date: Sun, 9 Oct 2011 12:39:37 +0400 Subject: [PATCH 07/14] Added JetTreeVisitorVoid, 'isBreakable' method instead of 'flowInformationProvider.isBreakable' --- .../jetbrains/jet/lang/psi/JetExpression.java | 2 +- .../jet/lang/psi/JetTreeVisitorVoid.java | 728 ++++++++++++++++++ .../jet/lang/types/JetTypeInferrer.java | 17 +- 3 files changed, 744 insertions(+), 3 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTreeVisitorVoid.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetExpression.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetExpression.java index 10cb7b02400..82864490542 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetExpression.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetExpression.java @@ -7,7 +7,7 @@ import org.jetbrains.jet.JetNodeType; /** * @author max */ -public class JetExpression extends JetElement { +public abstract class JetExpression extends JetElement { public JetExpression(@NotNull ASTNode node) { super(node); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTreeVisitorVoid.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTreeVisitorVoid.java new file mode 100644 index 00000000000..6b2e4de36e5 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTreeVisitorVoid.java @@ -0,0 +1,728 @@ +package org.jetbrains.jet.lang.psi; + +import java.util.List; + +/** + * @author svtk + */ +public class JetTreeVisitorVoid extends JetVisitorVoid { + @Override + public void visitNamespace(JetNamespace namespace) { + List importDirectives = namespace.getImportDirectives(); + for (JetImportDirective directive : importDirectives) { + directive.accept(this); + } + List declarations = namespace.getDeclarations(); + for (JetDeclaration declaration : declarations) { + declaration.accept(this); + } + } + + @Override + public void visitClass(JetClass klass) { + List declarations = klass.getDeclarations(); + for (JetDeclaration declaration : declarations) { + declaration.accept(this); + } + } + + @Override + public void visitClassObject(JetClassObject classObject) { + JetObjectDeclaration objectDeclaration = classObject.getObjectDeclaration(); + if (objectDeclaration != null) { + objectDeclaration.accept(this); + } + } + + @Override + public void visitConstructor(JetConstructor constructor) { + visitDeclarationWithBody(constructor); + } + + @Override + public void visitNamedFunction(JetNamedFunction function) { + visitDeclarationWithBody(function); + } + + @Override + public void visitProperty(JetProperty property) { + List accessors = property.getAccessors(); + for (JetPropertyAccessor accessor : accessors) { + accessor.accept(this); + } + JetExpression initializer = property.getInitializer(); + if (initializer != null) { + initializer.accept(this); + } + } + + @Override + public void visitTypedef(JetTypedef typedef) { + super.visitTypedef(typedef); + } + + @Override + public void visitJetFile(JetFile file) { + JetNamespace rootNamespace = file.getRootNamespace(); + rootNamespace.accept(this); + } + + @Override + public void visitImportDirective(JetImportDirective importDirective) { + super.visitImportDirective(importDirective); + } + + @Override + public void visitClassBody(JetClassBody classBody) { + List declarations = classBody.getDeclarations(); + for (JetDeclaration declaration : declarations) { + declaration.accept(this); + } + List secondaryConstructors = classBody.getSecondaryConstructors(); + for (JetConstructor constructor : secondaryConstructors) { + constructor.accept(this); + } + } + + @Override + public void visitNamespaceBody(JetNamespaceBody body) { + List declarations = body.getDeclarations(); + for (JetDeclaration declaration : declarations) { + declaration.accept(this); + } + } + + @Override + public void visitModifierList(JetModifierList list) { + super.visitModifierList(list); + } + + @Override + public void visitAnnotation(JetAnnotation annotation) { + super.visitAnnotation(annotation); + } + + @Override + public void visitAnnotationEntry(JetAnnotationEntry annotationEntry) { + super.visitAnnotationEntry(annotationEntry); + } + + @Override + public void visitTypeParameterList(JetTypeParameterList list) { + List parameters = list.getParameters(); + for (JetTypeParameter parameter : parameters) { + parameter.accept(this); + } + } + + @Override + public void visitTypeParameter(JetTypeParameter parameter) { + super.visitTypeParameter(parameter); + } + + @Override + public void visitEnumEntry(JetEnumEntry enumEntry) { + List delegationSpecifiers = enumEntry.getDelegationSpecifiers(); + for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) { + delegationSpecifier.accept(this); + } + JetModifierList modifierList = enumEntry.getModifierList(); + if (modifierList != null) { + modifierList.accept(this); + } + } + + @Override + public void visitParameterList(JetParameterList list) { + List parameters = list.getParameters(); + for (JetParameter parameter : parameters) { + parameter.accept(this); + } + } + + @Override + public void visitParameter(JetParameter parameter) { + super.visitParameter(parameter); + } + + @Override + public void visitDelegationSpecifierList(JetDelegationSpecifierList list) { + List delegationSpecifiers = list.getDelegationSpecifiers(); + for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) { + delegationSpecifier.accept(this); + } + } + + @Override + public void visitDelegationSpecifier(JetDelegationSpecifier specifier) { + super.visitDelegationSpecifier(specifier); + } + + @Override + public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) { + super.visitDelegationByExpressionSpecifier(specifier); + } + + @Override + public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) { + super.visitDelegationToSuperCallSpecifier(call); + } + + @Override + public void visitDelegationToSuperClassSpecifier(JetDelegatorToSuperClass specifier) { + super.visitDelegationToSuperClassSpecifier(specifier); + } + + @Override + public void visitDelegationToThisCall(JetDelegatorToThisCall thisCall) { + super.visitDelegationToThisCall(thisCall); + } + + @Override + public void visitTypeReference(JetTypeReference typeReference) { + super.visitTypeReference(typeReference); + } + + @Override + public void visitValueArgumentList(JetValueArgumentList list) { + List arguments = list.getArguments(); + for (JetValueArgument argument : arguments) { + argument.accept(this); + } + } + + @Override + public void visitArgument(JetValueArgument argument) { + super.visitArgument(argument); + } + + @Override + public void visitLoopExpression(JetLoopExpression loopExpression) { + JetExpression body = loopExpression.getBody(); + if (body != null) { + body.accept(this); + } + } + + @Override + public void visitConstantExpression(JetConstantExpression expression) { + super.visitConstantExpression(expression); + } + + @Override + public void visitSimpleNameExpression(JetSimpleNameExpression expression) { + super.visitSimpleNameExpression(expression); + } + + @Override + public void visitReferenceExpression(JetReferenceExpression expression) { + super.visitReferenceExpression(expression); + } + + @Override + public void visitTupleExpression(JetTupleExpression expression) { + super.visitTupleExpression(expression); + } + + @Override + public void visitPrefixExpression(JetPrefixExpression expression) { + JetExpression baseExpression = expression.getBaseExpression(); + if (baseExpression != null) { + baseExpression.accept(this); + } + } + + @Override + public void visitPostfixExpression(JetPostfixExpression expression) { + JetExpression baseExpression = expression.getBaseExpression(); + baseExpression.accept(this); + } + + @Override + public void visitUnaryExpression(JetUnaryExpression expression) { + JetExpression baseExpression = expression.getBaseExpression(); + assert baseExpression != null; + baseExpression.accept(this); + } + + @Override + public void visitBinaryExpression(JetBinaryExpression expression) { + JetExpression left = expression.getLeft(); + left.accept(this); + JetExpression right = expression.getRight(); + if (right != null) { + right.accept(this); + } + super.visitBinaryExpression(expression); + } + + @Override + public void visitReturnExpression(JetReturnExpression expression) { + JetExpression returnedExpression = expression.getReturnedExpression(); + if (returnedExpression != null) { + returnedExpression.accept(this); + } + } + + @Override + public void visitLabelQualifiedExpression(JetLabelQualifiedExpression expression) { + JetExpression labeledExpression = expression.getLabeledExpression(); + if (labeledExpression != null) { + labeledExpression.accept(this); + } + } + + @Override + public void visitThrowExpression(JetThrowExpression expression) { + JetExpression thrownExpression = expression.getThrownExpression(); + if (thrownExpression != null) { + thrownExpression.accept(this); + } + } + + @Override + public void visitBreakExpression(JetBreakExpression expression) { + super.visitBreakExpression(expression); + } + + @Override + public void visitContinueExpression(JetContinueExpression expression) { + super.visitContinueExpression(expression); + } + + @Override + public void visitIfExpression(JetIfExpression expression) { + JetExpression condition = expression.getCondition(); + if (condition != null) { + condition.accept(this); + } + JetExpression then = expression.getThen(); + if (then != null) { + then.accept(this); + } + JetExpression anElse = expression.getElse(); + if (anElse != null) { + anElse.accept(this); + } + } + + @Override + public void visitWhenExpression(JetWhenExpression expression) { + List entries = expression.getEntries(); + for (JetWhenEntry entry : entries) { + entry.accept(this); + } + JetExpression subjectExpression = expression.getSubjectExpression(); + if (subjectExpression != null) { + subjectExpression.accept(this); + } + } + + @Override + public void visitTryExpression(JetTryExpression expression) { + JetBlockExpression tryBlock = expression.getTryBlock(); + tryBlock.accept(this); + List catchClauses = expression.getCatchClauses(); + for (JetCatchClause catchClause : catchClauses) { + catchClause.accept(this); + } + JetFinallySection finallyBlock = expression.getFinallyBlock(); + if (finallyBlock != null) { + finallyBlock.accept(this); + } + } + + @Override + public void visitForExpression(JetForExpression expression) { + JetParameter loopParameter = expression.getLoopParameter(); + if (loopParameter != null) { + loopParameter.accept(this); + } + JetExpression loopRange = expression.getLoopRange(); + if (loopRange != null) { + loopRange.accept(this); + } + visitLoopExpression(expression); + } + + @Override + public void visitWhileExpression(JetWhileExpression expression) { + JetExpression condition = expression.getCondition(); + if (condition != null) { + condition.accept(this); + } + visitLoopExpression(expression); + } + + @Override + public void visitDoWhileExpression(JetDoWhileExpression expression) { + JetExpression condition = expression.getCondition(); + if (condition != null) { + condition.accept(this); + } + visitLoopExpression(expression); + } + + @Override + public void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression) { + JetFunctionLiteral functionLiteral = expression.getFunctionLiteral(); + functionLiteral.accept(this); + visitDeclarationWithBody(expression); + } + + @Override + public void visitAnnotatedExpression(JetAnnotatedExpression expression) { + JetExpression baseExpression = expression.getBaseExpression(); + baseExpression.accept(this); + } + + @Override + public void visitCallExpression(JetCallExpression expression) { + JetExpression calleeExpression = expression.getCalleeExpression(); + if (calleeExpression != null) { + calleeExpression.accept(this); + } + } + + @Override + public void visitArrayAccessExpression(JetArrayAccessExpression expression) { + JetExpression arrayExpression = expression.getArrayExpression(); + arrayExpression.accept(this); + List indexExpressions = expression.getIndexExpressions(); + for (JetExpression indexExpression : indexExpressions) { + indexExpression.accept(this); + } + } + + @Override + public void visitQualifiedExpression(JetQualifiedExpression expression) { + JetExpression receiver = expression.getReceiverExpression(); + receiver.accept(this); + JetExpression selector = expression.getSelectorExpression(); + if (selector != null) { + selector.accept(this); + } + } + + @Override + public void visitHashQualifiedExpression(JetHashQualifiedExpression expression) { + visitQualifiedExpression(expression); + } + + @Override + public void visitDotQualifiedExpression(JetDotQualifiedExpression expression) { + visitQualifiedExpression(expression); + } + + @Override + public void visitPredicateExpression(JetPredicateExpression expression) { + visitQualifiedExpression(expression); + } + + @Override + public void visitSafeQualifiedExpression(JetSafeQualifiedExpression expression) { + visitQualifiedExpression(expression); + } + + @Override + public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) { + JetObjectDeclaration objectDeclaration = expression.getObjectDeclaration(); + objectDeclaration.accept(this); + } + + @Override + public void visitRootNamespaceExpression(JetRootNamespaceExpression expression) { + super.visitRootNamespaceExpression(expression); + } + + @Override + public void visitBlockExpression(JetBlockExpression expression) { + List statements = expression.getStatements(); + for (JetElement statement : statements) { + statement.accept(this); + } + } + + @Override + public void visitCatchSection(JetCatchClause catchClause) { + JetParameter catchParameter = catchClause.getCatchParameter(); + if (catchParameter != null) { + catchParameter.accept(this); + } + JetExpression catchBody = catchClause.getCatchBody(); + if (catchBody != null) { + catchBody.accept(this); + } + } + + @Override + public void visitFinallySection(JetFinallySection finallySection) { + JetBlockExpression finalExpression = finallySection.getFinalExpression(); + finalExpression.accept(this); + } + + @Override + public void visitTypeArgumentList(JetTypeArgumentList typeArgumentList) { + List arguments = typeArgumentList.getArguments(); + for (JetTypeProjection argument : arguments) { + argument.accept(this); + } + } + + @Override + public void visitThisExpression(JetThisExpression expression) { + JetReferenceExpression thisReference = expression.getThisReference(); + thisReference.accept(this); + JetTypeReference superTypeQualifier = expression.getSuperTypeQualifier(); + if (superTypeQualifier != null) { + superTypeQualifier.accept(this); + } + visitLabelQualifiedExpression(expression); + } + + @Override + public void visitParenthesizedExpression(JetParenthesizedExpression expression) { + JetExpression innerExpression = expression.getExpression(); + if (innerExpression != null) { + innerExpression.accept(this); + } + } + + @Override + public void visitInitializerList(JetInitializerList list) { + List initializers = list.getInitializers(); + for (JetDelegationSpecifier initializer : initializers) { + initializer.accept(this); + } + } + + @Override + public void visitAnonymousInitializer(JetClassInitializer initializer) { + JetExpression body = initializer.getBody(); + body.accept(this); + } + + @Override + public void visitPropertyAccessor(JetPropertyAccessor accessor) { + visitDeclarationWithBody(accessor); + } + + @Override + public void visitTypeConstraintList(JetTypeConstraintList list) { + List constraints = list.getConstraints(); + for (JetTypeConstraint constraint : constraints) { + constraint.accept(this); + } + } + + @Override + public void visitTypeConstraint(JetTypeConstraint constraint) { + JetSimpleNameExpression subjectTypeParameterName = constraint.getSubjectTypeParameterName(); + if (subjectTypeParameterName != null) { + subjectTypeParameterName.accept(this); + } + } + + @Override + public void visitUserType(JetUserType type) { + super.visitUserType(type); + } + + @Override + public void visitTupleType(JetTupleType type) { + super.visitTupleType(type); + } + + @Override + public void visitFunctionType(JetFunctionType type) { + super.visitFunctionType(type); + } + + @Override + public void visitSelfType(JetSelfType type) { + super.visitSelfType(type); + } + + @Override + public void visitBinaryWithTypeRHSExpression(JetBinaryExpressionWithTypeRHS expression) { + JetExpression left = expression.getLeft(); + left.accept(this); + JetTypeReference right = expression.getRight(); + if (right != null) { + right.accept(this); + } + } + + @Override + public void visitStringTemplateExpression(JetStringTemplateExpression expression) { + JetStringTemplateEntry[] entries = expression.getEntries(); + for (JetStringTemplateEntry entry : entries) { + entry.accept(this); + } + } + + @Override + public void visitNamedDeclaration(JetNamedDeclaration declaration) { + super.visitNamedDeclaration(declaration); + } + + @Override + public void visitNullableType(JetNullableType nullableType) { + super.visitNullableType(nullableType); + } + + @Override + public void visitTypeProjection(JetTypeProjection typeProjection) { + super.visitTypeProjection(typeProjection); + } + + @Override + public void visitWhenEntry(JetWhenEntry jetWhenEntry) { + JetExpression expression = jetWhenEntry.getExpression(); + if (expression != null) { + expression.accept(this); + } + JetWhenCondition[] conditions = jetWhenEntry.getConditions(); + for (JetWhenCondition condition : conditions) { + condition.accept(this); + } + } + + @Override + public void visitIsExpression(JetIsExpression expression) { + JetExpression leftHandSide = expression.getLeftHandSide(); + leftHandSide.accept(this); + JetSimpleNameExpression operationReference = expression.getOperationReference(); + operationReference.accept(this); + JetPattern pattern = expression.getPattern(); + if (pattern != null) { + pattern.accept(this); + } + } + + @Override + public void visitWhenConditionCall(JetWhenConditionCall condition) { + JetExpression callSuffixExpression = condition.getCallSuffixExpression(); + if (callSuffixExpression != null) { + callSuffixExpression.accept(this); + } + } + + @Override + public void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition) { + JetPattern pattern = condition.getPattern(); + if (pattern != null) { + pattern.accept(this); + } + } + + @Override + public void visitWhenConditionInRange(JetWhenConditionInRange condition) { + JetSimpleNameExpression operationReference = condition.getOperationReference(); + operationReference.accept(this); + JetExpression rangeExpression = condition.getRangeExpression(); + if (rangeExpression != null) { + rangeExpression.accept(this); + } + } + + @Override + public void visitTypePattern(JetTypePattern pattern) { + super.visitTypePattern(pattern); + } + + @Override + public void visitWildcardPattern(JetWildcardPattern pattern) { + super.visitWildcardPattern(pattern); + } + + @Override + public void visitExpressionPattern(JetExpressionPattern pattern) { + JetExpression expression = pattern.getExpression(); + expression.accept(this); + } + + @Override + public void visitTuplePattern(JetTuplePattern pattern) { + List entries = pattern.getEntries(); + for (JetTuplePatternEntry entry : entries) { + entry.accept(this); + } + } + + @Override + public void visitDecomposerPattern(JetDecomposerPattern pattern) { + JetTuplePattern argumentList = pattern.getArgumentList(); + argumentList.accept(this); + JetExpression decomposerExpression = pattern.getDecomposerExpression(); + if (decomposerExpression != null) { + decomposerExpression.accept(this); + } + } + + @Override + public void visitObjectDeclaration(JetObjectDeclaration objectDeclaration) { + List declarations = objectDeclaration.getDeclarations(); + for (JetDeclaration declaration : declarations) { + declaration.accept(this); + } + JetDelegationSpecifierList delegationSpecifierList = objectDeclaration.getDelegationSpecifierList(); + if (delegationSpecifierList != null) { + delegationSpecifierList.accept(this); + } + } + + @Override + public void visitBindingPattern(JetBindingPattern pattern) { + JetWhenCondition condition = pattern.getCondition(); + if (condition != null) { + condition.accept(this); + } + JetProperty variableDeclaration = pattern.getVariableDeclaration(); + variableDeclaration.accept(this); + } + + @Override + public void visitStringTemplateEntry(JetStringTemplateEntry entry) { + JetExpression expression = entry.getExpression(); + if (expression != null) { + expression.accept(this); + } + } + + @Override + public void visitStringTemplateEntryWithExpression(JetStringTemplateEntryWithExpression entry) { + visitStringTemplateEntry(entry); + } + + @Override + public void visitBlockStringTemplateEntry(JetBlockStringTemplateEntry entry) { + visitStringTemplateEntry(entry); + } + + @Override + public void visitSimpleNameStringTemplateEntry(JetSimpleNameStringTemplateEntry entry) { + visitStringTemplateEntry(entry); + } + + @Override + public void visitLiteralStringTemplateEntry(JetLiteralStringTemplateEntry entry) { + visitStringTemplateEntry(entry); + } + + @Override + public void visitEscapeStringTemplateEntry(JetEscapeStringTemplateEntry entry) { + visitStringTemplateEntry(entry); + } + + private void visitDeclarationWithBody(JetDeclarationWithBody declaration) { + JetExpression bodyExpression = declaration.getBodyExpression(); + if (bodyExpression != null) { + bodyExpression.accept(this); + } + List valueParameters = declaration.getValueParameters(); + for (JetParameter valueParameter : valueParameters) { + valueParameter.accept(this); + } + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 58f3149be7e..d188f7e43b4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -1837,12 +1837,25 @@ public class JetTypeInferrer { DataFlowInfo conditionInfo = condition == null ? context.dataFlowInfo : extractDataFlowInfoFromCondition(condition, true, scopeToExtend, context); getTypeWithNewScopeAndDataFlowInfo(scopeToExtend, body, conditionInfo, context); } - if (!flowInformationProvider.isBreakable(expression)) { + if (!isBreakable(expression)) { // resultScope = newWritableScopeImpl(); resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false, null, context); } return context.services.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType); } + + private boolean isBreakable(JetLoopExpression expression) { + final boolean[] result = new boolean[1]; + result[0] = false; + expression.accept(new JetTreeVisitorVoid() { + @Override + public void visitBreakExpression(JetBreakExpression expression) { + result[0] = true; + } + }); + + return result[0]; + } @Override public JetType visitDoWhileExpression(JetDoWhileExpression expression, TypeInferenceContext contextWithExpectedType) { @@ -1867,7 +1880,7 @@ public class JetTypeInferrer { } JetExpression condition = expression.getCondition(); checkCondition(conditionScope, condition, context); - if (!flowInformationProvider.isBreakable(expression)) { + if (!isBreakable(expression)) { // resultScope = newWritableScopeImpl(); resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false, null, context); } From fc6879e7fd0960a87c4bd156e50574304cf60151 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Mon, 10 Oct 2011 09:01:02 +0200 Subject: [PATCH 08/14] type info for tuples and functions --- .../jetbrains/jet/codegen/ClosureCodegen.java | 9 ++- .../jet/codegen/ExpressionCodegen.java | 3 +- .../lang/types/ProjectionErasingJetType.java | 63 +++++++++++++++++++ .../jet/codegen/ClosuresGenTest.java | 1 + .../jet/codegen/NamespaceGenTest.java | 14 +++++ .../jet/codegen/PatternMatchingTest.java | 8 +-- stdlib/src/jet/DefaultJetObject.java | 19 ++++++ stdlib/src/jet/ExtensionFunction0.java | 8 ++- stdlib/src/jet/ExtensionFunction1.java | 8 ++- stdlib/src/jet/ExtensionFunction2.java | 8 ++- stdlib/src/jet/ExtensionFunction3.java | 8 ++- stdlib/src/jet/Function0.java | 8 ++- stdlib/src/jet/Function1.java | 8 ++- stdlib/src/jet/Function2.java | 8 ++- stdlib/src/jet/Function3.java | 8 ++- stdlib/src/jet/Tuple0.java | 10 ++- stdlib/src/jet/Tuple1.java | 7 ++- stdlib/src/jet/Tuple10.java | 7 ++- stdlib/src/jet/Tuple11.java | 7 ++- stdlib/src/jet/Tuple12.java | 7 ++- stdlib/src/jet/Tuple13.java | 7 ++- stdlib/src/jet/Tuple14.java | 7 ++- stdlib/src/jet/Tuple15.java | 7 ++- stdlib/src/jet/Tuple16.java | 7 ++- stdlib/src/jet/Tuple17.java | 7 ++- stdlib/src/jet/Tuple18.java | 7 ++- stdlib/src/jet/Tuple19.java | 7 ++- stdlib/src/jet/Tuple2.java | 7 ++- stdlib/src/jet/Tuple20.java | 7 ++- stdlib/src/jet/Tuple21.java | 7 ++- stdlib/src/jet/Tuple22.java | 7 ++- stdlib/src/jet/Tuple3.java | 7 ++- stdlib/src/jet/Tuple4.java | 7 ++- stdlib/src/jet/Tuple5.java | 7 ++- stdlib/src/jet/Tuple6.java | 7 ++- stdlib/src/jet/Tuple7.java | 7 ++- stdlib/src/jet/Tuple8.java | 7 ++- stdlib/src/jet/Tuple9.java | 7 ++- stdlib/src/jet/typeinfo/TypeInfo.java | 2 +- 39 files changed, 285 insertions(+), 62 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/types/ProjectionErasingJetType.java create mode 100644 stdlib/src/jet/DefaultJetObject.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 864111bee96..cccef2b42c8 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -13,6 +13,7 @@ import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.ProjectionErasingJetType; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -117,7 +118,7 @@ public class ClosureCodegen { final Type enclosingType = context.enclosingClassType(state.getTypeMapper()); if (enclosingType == null) captureThis = false; - final Method constructor = generateConstructor(funClass, captureThis); + final Method constructor = generateConstructor(funClass, captureThis, funDescriptor.getReturnType()); if (captureThis) { cv.visitField(Opcodes.ACC_PRIVATE, "this$0", enclosingType.getDescriptor(), null, null); @@ -175,7 +176,7 @@ public class ClosureCodegen { mv.visitEnd(); } - private Method generateConstructor(String funClass, boolean captureThis) { + private Method generateConstructor(String funClass, boolean captureThis, JetType returnType) { int argCount = closure.size(); if (captureThis) { @@ -199,9 +200,11 @@ public class ClosureCodegen { final MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "", constructor.getDescriptor(), null, new String[0]); mv.visitCode(); InstructionAdapter iv = new InstructionAdapter(mv); + ExpressionCodegen expressionCodegen = new ExpressionCodegen(mv, null, Type.VOID_TYPE, context, state); iv.load(0, Type.getObjectType(funClass)); - iv.invokespecial(funClass, "", "()V"); + expressionCodegen.generateTypeInfo(new ProjectionErasingJetType(returnType)); + iv.invokespecial(funClass, "", "(Ljet/typeinfo/TypeInfo;)V"); i = 1; for (Type type : argTypes) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index ea7afc3dd7b..f231cdf3426 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -2318,7 +2318,7 @@ public class ExpressionCodegen extends JetVisitor { final String className = "jet/Tuple" + entries.size(); Type tupleType = Type.getObjectType(className); - StringBuilder signature = new StringBuilder("("); + StringBuilder signature = new StringBuilder("(Ljet/typeinfo/TypeInfo;"); for (int i = 0; i != entries.size(); ++i) { signature.append("Ljava/lang/Object;"); } @@ -2326,6 +2326,7 @@ public class ExpressionCodegen extends JetVisitor { v.anew(tupleType); v.dup(); + generateTypeInfo(new ProjectionErasingJetType(bindingContext.get(BindingContext.EXPRESSION_TYPE, expression))); for (JetExpression entry : entries) { gen(entry, OBJECT_TYPE); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/ProjectionErasingJetType.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/ProjectionErasingJetType.java new file mode 100644 index 00000000000..76956d129e5 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/ProjectionErasingJetType.java @@ -0,0 +1,63 @@ +package org.jetbrains.jet.lang.types; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; + +import java.util.*; + +/** + * @author alex.tkachman + * + * Utility class used by back-end to + */ +public class ProjectionErasingJetType implements JetType { + private final JetType delegate; + private List arguments; + + public ProjectionErasingJetType(JetType delegate) { + this.delegate = delegate; + arguments = new ArrayList(); + for(TypeProjection tp : delegate.getArguments()) { + arguments.add(new TypeProjection(Variance.INVARIANT, tp.getType())); + } + } + + @NotNull + @Override + public TypeConstructor getConstructor() { + return delegate.getConstructor(); + } + + @NotNull + @Override + public List getArguments() { + return arguments; + } + + @Override + public boolean isNullable() { + return false; + } + + @NotNull + @Override + public JetScope getMemberScope() { + return delegate.getMemberScope(); + } + + @Override + public List getAnnotations() { + return delegate.getAnnotations(); + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return ((obj instanceof ProjectionErasingJetType) && delegate.equals(((ProjectionErasingJetType)obj).delegate)) || delegate.equals(obj); + } +} diff --git a/idea/tests/org/jetbrains/jet/codegen/ClosuresGenTest.java b/idea/tests/org/jetbrains/jet/codegen/ClosuresGenTest.java index 4a1174ba55a..7d5f4a68fc8 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ClosuresGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ClosuresGenTest.java @@ -6,6 +6,7 @@ package org.jetbrains.jet.codegen; public class ClosuresGenTest extends CodegenTestCase { public void testSimplestClosure() throws Exception { blackBoxFile("classes/simplestClosure.jet"); + System.out.println(generateToText()); } public void testSimplestClosureAndBoxing() throws Exception { diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index a1f2940a78e..5c4167442fa 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -2,6 +2,8 @@ package org.jetbrains.jet.codegen; import jet.IntRange; import jet.Tuple2; +import jet.Tuple3; +import jet.Tuple4; import jet.typeinfo.TypeInfo; import org.jetbrains.jet.parsing.JetParsingTest; @@ -9,6 +11,7 @@ import java.awt.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; /** * @author yole @@ -489,12 +492,23 @@ public class NamespaceGenTest extends CodegenTestCase { public void testTupleLiteral() throws Exception { loadText("fun foo() = (1, \"foo\")"); + System.out.println(generateToText()); final Method main = generateFunction(); Tuple2 tuple2 = (Tuple2) main.invoke(null); assertEquals(1, tuple2._1); assertEquals("foo", tuple2._2); } + public void testParametrizedTupleLiteral() throws Exception { + loadText("fun E.foo(extra: java.util.List) = (1, \"foo\", this, extra)"); + System.out.println(generateToText()); + final Method main = generateFunction(); + Tuple4 tuple4 = (Tuple4) main.invoke(null, "aaa", Arrays.asList(10), TypeInfo.STRING_TYPE_INFO, TypeInfo.INT_TYPE_INFO); + assertEquals(1, tuple4._1); + assertEquals("foo", tuple4._2); + assertEquals("aaa", tuple4._3); + } + public void testPredicateOperator() throws Exception { loadText("fun foo(s: String) = s?startsWith(\"J\")"); final Method main = generateFunction(); diff --git a/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java b/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java index 60337ed4ff2..667415f53f3 100644 --- a/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java @@ -90,13 +90,13 @@ public class PatternMatchingTest extends CodegenTestCase { Method foo = generateFunction(); final Object result; try { - result = foo.invoke(null, new Tuple2(1, 2)); + result = foo.invoke(null, new Tuple2(null, 1, 2)); } catch (Exception e) { System.out.println(generateToText()); throw e; } assertEquals("one,two", result); - assertEquals("something", foo.invoke(null, new Tuple2("not", "tuple"))); + assertEquals("something", foo.invoke(null, new Tuple2(null, "not", "tuple"))); } public void testCall() throws Exception { @@ -119,8 +119,8 @@ public class PatternMatchingTest extends CodegenTestCase { public void testNames() throws Exception { loadText("fun foo(x: (Any, Any)) = when(x) { is (val a is String, *) => a; else => \"something\" }"); Method foo = generateFunction(); - assertEquals("JetBrains", foo.invoke(null, new Tuple2("JetBrains", "s.r.o."))); - assertEquals("something", foo.invoke(null, new Tuple2(1, 2))); + assertEquals("JetBrains", foo.invoke(null, new Tuple2(null, "JetBrains", "s.r.o."))); + assertEquals("something", foo.invoke(null, new Tuple2(null, 1, 2))); } public void testMultipleConditions() throws Exception { diff --git a/stdlib/src/jet/DefaultJetObject.java b/stdlib/src/jet/DefaultJetObject.java new file mode 100644 index 00000000000..017a47df4a7 --- /dev/null +++ b/stdlib/src/jet/DefaultJetObject.java @@ -0,0 +1,19 @@ +package jet; + +import jet.typeinfo.TypeInfo; + +/** + * @author alex.tkachman + */ +public class DefaultJetObject implements JetObject { + private TypeInfo typeInfo; + + protected DefaultJetObject(TypeInfo typeInfo) { + this.typeInfo = typeInfo; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } +} diff --git a/stdlib/src/jet/ExtensionFunction0.java b/stdlib/src/jet/ExtensionFunction0.java index 099f3bbe3a4..9d2e12fcc47 100644 --- a/stdlib/src/jet/ExtensionFunction0.java +++ b/stdlib/src/jet/ExtensionFunction0.java @@ -3,7 +3,13 @@ */ package jet; -public abstract class ExtensionFunction0 { +import jet.typeinfo.TypeInfo; + +public abstract class ExtensionFunction0 extends DefaultJetObject{ + protected ExtensionFunction0(TypeInfo typeInfo) { + super(typeInfo); + } + public abstract R invoke(E receiver); @Override diff --git a/stdlib/src/jet/ExtensionFunction1.java b/stdlib/src/jet/ExtensionFunction1.java index 782b8ec3948..2a75a41acf6 100644 --- a/stdlib/src/jet/ExtensionFunction1.java +++ b/stdlib/src/jet/ExtensionFunction1.java @@ -3,7 +3,13 @@ */ package jet; -public abstract class ExtensionFunction1 { +import jet.typeinfo.TypeInfo; + +public abstract class ExtensionFunction1 extends DefaultJetObject{ + protected ExtensionFunction1(TypeInfo typeInfo) { + super(typeInfo); + } + public abstract R invoke(E receiver, D d); @Override diff --git a/stdlib/src/jet/ExtensionFunction2.java b/stdlib/src/jet/ExtensionFunction2.java index 7c885c741fa..a7ffa19687a 100644 --- a/stdlib/src/jet/ExtensionFunction2.java +++ b/stdlib/src/jet/ExtensionFunction2.java @@ -3,7 +3,13 @@ */ package jet; -public abstract class ExtensionFunction2 { +import jet.typeinfo.TypeInfo; + +public abstract class ExtensionFunction2 extends DefaultJetObject{ + protected ExtensionFunction2(TypeInfo typeInfo) { + super(typeInfo); + } + public abstract R invoke(E receiver, D1 d1, D2 d2); @Override diff --git a/stdlib/src/jet/ExtensionFunction3.java b/stdlib/src/jet/ExtensionFunction3.java index 0b034418dc5..54dd96f5f32 100644 --- a/stdlib/src/jet/ExtensionFunction3.java +++ b/stdlib/src/jet/ExtensionFunction3.java @@ -3,7 +3,13 @@ */ package jet; -public abstract class ExtensionFunction3 { +import jet.typeinfo.TypeInfo; + +public abstract class ExtensionFunction3 extends DefaultJetObject{ + protected ExtensionFunction3(TypeInfo typeInfo) { + super(typeInfo); + } + public abstract R invoke(E receiver, D1 d1, D2 d2, D3 d3); @Override diff --git a/stdlib/src/jet/Function0.java b/stdlib/src/jet/Function0.java index 917010163f2..67515b604e1 100644 --- a/stdlib/src/jet/Function0.java +++ b/stdlib/src/jet/Function0.java @@ -3,7 +3,13 @@ */ package jet; -public abstract class Function0 { +import jet.typeinfo.TypeInfo; + +public abstract class Function0 extends DefaultJetObject { + protected Function0(TypeInfo typeInfo) { + super(typeInfo); + } + public abstract R invoke(); @Override diff --git a/stdlib/src/jet/Function1.java b/stdlib/src/jet/Function1.java index ba1846107e1..345a47cb0a2 100644 --- a/stdlib/src/jet/Function1.java +++ b/stdlib/src/jet/Function1.java @@ -3,7 +3,13 @@ */ package jet; -public abstract class Function1 { +import jet.typeinfo.TypeInfo; + +public abstract class Function1 extends DefaultJetObject { + protected Function1(TypeInfo typeInfo) { + super(typeInfo); + } + public abstract R invoke(D d); @Override diff --git a/stdlib/src/jet/Function2.java b/stdlib/src/jet/Function2.java index 801e95c63f0..170b1969d0e 100644 --- a/stdlib/src/jet/Function2.java +++ b/stdlib/src/jet/Function2.java @@ -3,7 +3,13 @@ */ package jet; -public abstract class Function2 { +import jet.typeinfo.TypeInfo; + +public abstract class Function2 extends DefaultJetObject { + protected Function2(TypeInfo typeInfo) { + super(typeInfo); + } + public abstract R invoke(D1 d1, D2 d2); @Override diff --git a/stdlib/src/jet/Function3.java b/stdlib/src/jet/Function3.java index 81963444c97..54380062e6e 100644 --- a/stdlib/src/jet/Function3.java +++ b/stdlib/src/jet/Function3.java @@ -3,7 +3,13 @@ */ package jet; -public abstract class Function3 { +import jet.typeinfo.TypeInfo; + +public abstract class Function3 extends DefaultJetObject{ + protected Function3(TypeInfo typeInfo) { + super(typeInfo); + } + public abstract R invoke(D1 d1, D2 d2, D3 d3); @Override diff --git a/stdlib/src/jet/Tuple0.java b/stdlib/src/jet/Tuple0.java index 8d9db829584..34d12022230 100644 --- a/stdlib/src/jet/Tuple0.java +++ b/stdlib/src/jet/Tuple0.java @@ -1,10 +1,13 @@ package jet; +import jet.typeinfo.TypeInfo; + /** * @author alex.tkachman */ -public class Tuple0 { +public class Tuple0 implements JetObject { public static final Tuple0 INSTANCE = new Tuple0(); + private static final TypeInfo typeInfo = TypeInfo.getTypeInfo(Tuple0.class, false); private Tuple0() { } @@ -23,4 +26,9 @@ public class Tuple0 { public int hashCode() { return 239; } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } } \ No newline at end of file diff --git a/stdlib/src/jet/Tuple1.java b/stdlib/src/jet/Tuple1.java index fd9214be8d3..c50550d258b 100644 --- a/stdlib/src/jet/Tuple1.java +++ b/stdlib/src/jet/Tuple1.java @@ -1,9 +1,12 @@ package jet; -public class Tuple1 { +import jet.typeinfo.TypeInfo; + +public class Tuple1 extends DefaultJetObject { public final T1 _1; - public Tuple1(T1 t1) { + public Tuple1(TypeInfo typeInfo, T1 t1) { + super(typeInfo); _1 = t1; } diff --git a/stdlib/src/jet/Tuple10.java b/stdlib/src/jet/Tuple10.java index c8d6a0077a3..065ef8888ca 100644 --- a/stdlib/src/jet/Tuple10.java +++ b/stdlib/src/jet/Tuple10.java @@ -1,6 +1,8 @@ package jet; -public class Tuple10 { +import jet.typeinfo.TypeInfo; + +public class Tuple10 extends DefaultJetObject{ public final T1 _1; public final T2 _2; public final T3 _3; @@ -12,7 +14,8 @@ public class Tuple10 { public final T9 _9; public final T10 _10; - public Tuple10(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10) { + public Tuple10(TypeInfo typeInfo, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10) { + super(typeInfo); _1 = t1; _2 = t2; _3 = t3; diff --git a/stdlib/src/jet/Tuple11.java b/stdlib/src/jet/Tuple11.java index a662f9c7b31..dcf69b1920a 100644 --- a/stdlib/src/jet/Tuple11.java +++ b/stdlib/src/jet/Tuple11.java @@ -1,6 +1,8 @@ package jet; -public class Tuple11 { +import jet.typeinfo.TypeInfo; + +public class Tuple11 extends DefaultJetObject{ public final T1 _1; public final T2 _2; public final T3 _3; @@ -13,7 +15,8 @@ public class Tuple11 { public final T10 _10; public final T11 _11; - public Tuple11(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10, T11 t11) { + public Tuple11(TypeInfo typeInfo, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10, T11 t11) { + super(typeInfo); _1 = t1; _2 = t2; _3 = t3; diff --git a/stdlib/src/jet/Tuple12.java b/stdlib/src/jet/Tuple12.java index 2c003f48433..a0a55e4efc6 100644 --- a/stdlib/src/jet/Tuple12.java +++ b/stdlib/src/jet/Tuple12.java @@ -1,6 +1,8 @@ package jet; -public class Tuple12 { +import jet.typeinfo.TypeInfo; + +public class Tuple12 extends DefaultJetObject { public final T1 _1; public final T2 _2; public final T3 _3; @@ -14,7 +16,8 @@ public class Tuple12 { public final T11 _11; public final T12 _12; - public Tuple12(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10, T11 t11, T12 t12) { + public Tuple12(TypeInfo typeInfo, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10, T11 t11, T12 t12) { + super(typeInfo); _1 = t1; _2 = t2; _3 = t3; diff --git a/stdlib/src/jet/Tuple13.java b/stdlib/src/jet/Tuple13.java index bb2d40775d4..fff29fd6840 100644 --- a/stdlib/src/jet/Tuple13.java +++ b/stdlib/src/jet/Tuple13.java @@ -1,6 +1,8 @@ package jet; -public class Tuple13 { +import jet.typeinfo.TypeInfo; + +public class Tuple13 extends DefaultJetObject{ public final T1 _1; public final T2 _2; public final T3 _3; @@ -15,7 +17,8 @@ public class Tuple13 { public final T12 _12; public final T13 _13; - public Tuple13(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10, T11 t11, T12 t12, T13 t13) { + public Tuple13(TypeInfo typeInfo, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10, T11 t11, T12 t12, T13 t13) { + super(typeInfo); _1 = t1; _2 = t2; _3 = t3; diff --git a/stdlib/src/jet/Tuple14.java b/stdlib/src/jet/Tuple14.java index 11d3bb1f700..ed43c45f96d 100644 --- a/stdlib/src/jet/Tuple14.java +++ b/stdlib/src/jet/Tuple14.java @@ -1,6 +1,8 @@ package jet; -public class Tuple14 { +import jet.typeinfo.TypeInfo; + +public class Tuple14 extends DefaultJetObject{ public final T1 _1; public final T2 _2; public final T3 _3; @@ -16,7 +18,8 @@ public class Tuple14 { +import jet.typeinfo.TypeInfo; + +public class Tuple15 extends DefaultJetObject { public final T1 _1; public final T2 _2; public final T3 _3; @@ -17,7 +19,8 @@ public class Tuple15 { +import jet.typeinfo.TypeInfo; + +public class Tuple16 extends DefaultJetObject { public final T1 _1; public final T2 _2; public final T3 _3; @@ -18,7 +20,8 @@ public class Tuple16 { +import jet.typeinfo.TypeInfo; + +public class Tuple17 extends DefaultJetObject { public final T1 _1; public final T2 _2; public final T3 _3; @@ -19,7 +21,8 @@ public class Tuple17 { +import jet.typeinfo.TypeInfo; + +public class Tuple18 extends DefaultJetObject{ public final T1 _1; public final T2 _2; public final T3 _3; @@ -20,7 +22,8 @@ public class Tuple18 { +import jet.typeinfo.TypeInfo; + +public class Tuple19 extends DefaultJetObject { public final T1 _1; public final T2 _2; public final T3 _3; @@ -21,7 +23,8 @@ public class Tuple19 { +import jet.typeinfo.TypeInfo; + +public class Tuple2 extends DefaultJetObject { public final T1 _1; public final T2 _2; - public Tuple2(T1 t1, T2 t2) { + public Tuple2(TypeInfo typeInfo, T1 t1, T2 t2) { + super(typeInfo); _1 = t1; _2 = t2; } diff --git a/stdlib/src/jet/Tuple20.java b/stdlib/src/jet/Tuple20.java index a7afabf2e5a..21bc043be64 100644 --- a/stdlib/src/jet/Tuple20.java +++ b/stdlib/src/jet/Tuple20.java @@ -1,6 +1,8 @@ package jet; -public class Tuple20 { +import jet.typeinfo.TypeInfo; + +public class Tuple20 extends DefaultJetObject{ public final T1 _1; public final T2 _2; public final T3 _3; @@ -22,7 +24,8 @@ public class Tuple20 { +import jet.typeinfo.TypeInfo; + +public class Tuple21 extends DefaultJetObject { public final T1 _1; public final T2 _2; public final T3 _3; @@ -23,7 +25,8 @@ public class Tuple21 { +import jet.typeinfo.TypeInfo; + +public class Tuple22 extends DefaultJetObject { public final T1 _1; public final T2 _2; public final T3 _3; @@ -24,7 +26,8 @@ public class Tuple22 { +import jet.typeinfo.TypeInfo; + +public class Tuple3 extends DefaultJetObject { public final T1 _1; public final T2 _2; public final T3 _3; - public Tuple3(T1 t1, T2 t2, T3 t3) { + public Tuple3(TypeInfo typeInfo, T1 t1, T2 t2, T3 t3) { + super(typeInfo); _1 = t1; _2 = t2; _3 = t3; diff --git a/stdlib/src/jet/Tuple4.java b/stdlib/src/jet/Tuple4.java index a756455249f..743543503ef 100644 --- a/stdlib/src/jet/Tuple4.java +++ b/stdlib/src/jet/Tuple4.java @@ -1,12 +1,15 @@ package jet; -public class Tuple4 { +import jet.typeinfo.TypeInfo; + +public class Tuple4 extends DefaultJetObject { public final T1 _1; public final T2 _2; public final T3 _3; public final T4 _4; - public Tuple4(T1 t1, T2 t2, T3 t3, T4 t4) { + public Tuple4(TypeInfo typeInfo, T1 t1, T2 t2, T3 t3, T4 t4) { + super(typeInfo); _1 = t1; _2 = t2; _3 = t3; diff --git a/stdlib/src/jet/Tuple5.java b/stdlib/src/jet/Tuple5.java index b96edcea1e2..8ff54f422b6 100644 --- a/stdlib/src/jet/Tuple5.java +++ b/stdlib/src/jet/Tuple5.java @@ -1,13 +1,16 @@ package jet; -public class Tuple5 { +import jet.typeinfo.TypeInfo; + +public class Tuple5 extends DefaultJetObject{ public final T1 _1; public final T2 _2; public final T3 _3; public final T4 _4; public final T5 _5; - public Tuple5(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) { + public Tuple5(TypeInfo typeInfo, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) { + super(typeInfo); _1 = t1; _2 = t2; _3 = t3; diff --git a/stdlib/src/jet/Tuple6.java b/stdlib/src/jet/Tuple6.java index f8b778ac7d6..2b855a01fe8 100644 --- a/stdlib/src/jet/Tuple6.java +++ b/stdlib/src/jet/Tuple6.java @@ -1,6 +1,8 @@ package jet; -public class Tuple6 { +import jet.typeinfo.TypeInfo; + +public class Tuple6 extends DefaultJetObject { public final T1 _1; public final T2 _2; public final T3 _3; @@ -8,7 +10,8 @@ public class Tuple6 { public final T5 _5; public final T6 _6; - public Tuple6(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) { + public Tuple6(TypeInfo typeInfo, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) { + super(typeInfo); _1 = t1; _2 = t2; _3 = t3; diff --git a/stdlib/src/jet/Tuple7.java b/stdlib/src/jet/Tuple7.java index e5cc9969590..baf95a8339f 100644 --- a/stdlib/src/jet/Tuple7.java +++ b/stdlib/src/jet/Tuple7.java @@ -1,6 +1,8 @@ package jet; -public class Tuple7 { +import jet.typeinfo.TypeInfo; + +public class Tuple7 extends DefaultJetObject{ public final T1 _1; public final T2 _2; public final T3 _3; @@ -9,7 +11,8 @@ public class Tuple7 { public final T6 _6; public final T7 _7; - public Tuple7(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) { + public Tuple7(TypeInfo typeInfo, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) { + super(typeInfo); _1 = t1; _2 = t2; _3 = t3; diff --git a/stdlib/src/jet/Tuple8.java b/stdlib/src/jet/Tuple8.java index 6c066f3b8c0..f71bf7593be 100644 --- a/stdlib/src/jet/Tuple8.java +++ b/stdlib/src/jet/Tuple8.java @@ -1,6 +1,8 @@ package jet; -public class Tuple8 { +import jet.typeinfo.TypeInfo; + +public class Tuple8 extends DefaultJetObject{ public final T1 _1; public final T2 _2; public final T3 _3; @@ -10,7 +12,8 @@ public class Tuple8 { public final T7 _7; public final T8 _8; - public Tuple8(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) { + public Tuple8(TypeInfo typeInfo, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) { + super(typeInfo); _1 = t1; _2 = t2; _3 = t3; diff --git a/stdlib/src/jet/Tuple9.java b/stdlib/src/jet/Tuple9.java index bb83db5317d..7bc9da9ef7e 100644 --- a/stdlib/src/jet/Tuple9.java +++ b/stdlib/src/jet/Tuple9.java @@ -1,6 +1,8 @@ package jet; -public class Tuple9 { +import jet.typeinfo.TypeInfo; + +public class Tuple9 extends DefaultJetObject{ public final T1 _1; public final T2 _2; public final T3 _3; @@ -11,7 +13,8 @@ public class Tuple9 { public final T8 _8; public final T9 _9; - public Tuple9(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9) { + public Tuple9(TypeInfo typeInfo, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9) { + super(typeInfo); _1 = t1; _2 = t2; _3 = t3; diff --git a/stdlib/src/jet/typeinfo/TypeInfo.java b/stdlib/src/jet/typeinfo/TypeInfo.java index 19bc40b4a5e..57d13423562 100644 --- a/stdlib/src/jet/typeinfo/TypeInfo.java +++ b/stdlib/src/jet/typeinfo/TypeInfo.java @@ -22,7 +22,7 @@ public abstract class TypeInfo implements JetObject { public static final TypeInfo INT_TYPE_INFO = getTypeInfo(Integer.class, false); public static final TypeInfo LONG_TYPE_INFO = getTypeInfo(Long.class, false); public static final TypeInfo CHAR_TYPE_INFO = getTypeInfo(Character.class, false); - public static final TypeInfo BOOL_TYPE_INFO = getTypeInfo(Boolean.class, false); + public static final TypeInfo BOOLEAN_TYPE_INFO = getTypeInfo(Boolean.class, false); public static final TypeInfo FLOAT_TYPE_INFO = getTypeInfo(Float.class, false); public static final TypeInfo DOUBLE_TYPE_INFO = getTypeInfo(Double.class, false); From 868e024c936754242077c8ad1ca3803c809f06c1 Mon Sep 17 00:00:00 2001 From: svtk Date: Mon, 10 Oct 2011 20:45:42 +0400 Subject: [PATCH 09/14] More fixes for possible coercion to unit of type of last statement in block --- .../jet/lang/diagnostics/Errors.java | 1 + .../jet/lang/types/JetTypeInferrer.java | 88 +++++++++++++------ .../full/FunctionReturnTypes.jet | 38 ++++++++ idea/testData/codegen/regressions/kt343.jet | 10 ++- 4 files changed, 107 insertions(+), 30 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index ff09318972b..2f98129c988 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -192,6 +192,7 @@ public interface Errors { SimpleDiagnosticFactory RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY = SimpleDiagnosticFactory.create(ERROR, "Returns are not allowed for functions with expression body. Use block body in '{...}'"); SimpleDiagnosticFactory NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY = SimpleDiagnosticFactory.create(ERROR, "A 'return' expression required in a function with a block body ('{...}')"); ParameterizedDiagnosticFactory1 RETURN_TYPE_MISMATCH = ParameterizedDiagnosticFactory1.create(ERROR, "This function must return a value of type {0}"); + ParameterizedDiagnosticFactory1 EXPECTED_TYPE_MISMATCH = ParameterizedDiagnosticFactory1.create(ERROR, "Expected a value of type {0}"); ParameterizedDiagnosticFactory1 UPPER_BOUND_VIOLATED = ParameterizedDiagnosticFactory1.create(ERROR, "An upper bound {0} is violated"); // TODO : Message ParameterizedDiagnosticFactory1 FINAL_CLASS_OBJECT_UPPER_BOUND = ParameterizedDiagnosticFactory1.create(ERROR, "{0} is a final type, and thus a class object cannot extend it"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 05c1ff314f3..542f9aae729 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -423,42 +423,61 @@ public class JetTypeInferrer { trace.record(STATEMENT, statement); final JetExpression statementExpression = (JetExpression) statement; //TODO constructor assert context.expectedType != FORBIDDEN : "" - if (!iterator.hasNext() && context.expectedType != NO_EXPECTED_TYPE) { - if (coercionStrategyForLastExpression == CoercionStrategy.COERCION_TO_UNIT && JetStandardClasses.isUnit(context.expectedType)) { - // This implements coercion to Unit - TemporaryBindingTrace temporaryTraceExpectingUnit = TemporaryBindingTrace.create(trace); - final boolean[] mismatch = new boolean[1]; - ObservableBindingTrace errorInterceptingTrace = makeTraceInterceptingTypeMismatch(temporaryTraceExpectingUnit, statementExpression, mismatch); - newContext = newContext(errorInterceptingTrace, scope, newContext.dataFlowInfo, context.expectedType, context.expectedReturnType); - result = blockLevelVisitor.getType(statementExpression, newContext); - if (mismatch[0]) { - TemporaryBindingTrace temporaryTraceNoExpectedType = TemporaryBindingTrace.create(trace); - mismatch[0] = false; - ObservableBindingTrace interceptingTrace = makeTraceInterceptingTypeMismatch(temporaryTraceNoExpectedType, statementExpression, mismatch); - newContext = newContext(interceptingTrace, scope, newContext.dataFlowInfo, NO_EXPECTED_TYPE, context.expectedReturnType); + if (!iterator.hasNext()) { + if (context.expectedType != NO_EXPECTED_TYPE) { + if (coercionStrategyForLastExpression == CoercionStrategy.COERCION_TO_UNIT && JetStandardClasses.isUnit(context.expectedType)) { + // This implements coercion to Unit + TemporaryBindingTrace temporaryTraceExpectingUnit = TemporaryBindingTrace.create(trace); + final boolean[] mismatch = new boolean[1]; + ObservableBindingTrace errorInterceptingTrace = makeTraceInterceptingTypeMismatch(temporaryTraceExpectingUnit, statementExpression, mismatch); + newContext = newContext(errorInterceptingTrace, scope, newContext.dataFlowInfo, context.expectedType, context.expectedReturnType); result = blockLevelVisitor.getType(statementExpression, newContext); if (mismatch[0]) { - temporaryTraceExpectingUnit.commit(); + TemporaryBindingTrace temporaryTraceNoExpectedType = TemporaryBindingTrace.create(trace); + mismatch[0] = false; + ObservableBindingTrace interceptingTrace = makeTraceInterceptingTypeMismatch(temporaryTraceNoExpectedType, statementExpression, mismatch); + newContext = newContext(interceptingTrace, scope, newContext.dataFlowInfo, NO_EXPECTED_TYPE, context.expectedReturnType); + result = blockLevelVisitor.getType(statementExpression, newContext); + if (mismatch[0]) { + temporaryTraceExpectingUnit.commit(); + } + else { + temporaryTraceNoExpectedType.commit(); + } } else { - temporaryTraceNoExpectedType.commit(); + temporaryTraceExpectingUnit.commit(); } } else { - temporaryTraceExpectingUnit.commit(); + newContext = newContext(trace, scope, newContext.dataFlowInfo, context.expectedType, context.expectedReturnType); + result = blockLevelVisitor.getType(statementExpression, newContext); } - } else { - newContext = newContext(trace, scope, newContext.dataFlowInfo, context.expectedType, context.expectedReturnType); result = blockLevelVisitor.getType(statementExpression, newContext); + if (coercionStrategyForLastExpression == CoercionStrategy.COERCION_TO_UNIT) { + boolean mightBeUnit = false; + if (statementExpression instanceof JetDeclaration) { + mightBeUnit = true; + } + if (statementExpression instanceof JetBinaryExpression) { + JetBinaryExpression binaryExpression = (JetBinaryExpression) statementExpression; + IElementType operationType = binaryExpression.getOperationToken(); + if (operationType == JetTokens.EQ || assignmentOperationNames.containsKey(operationType)) { + mightBeUnit = true; + } + } + if (mightBeUnit) { + // TypeInferrerVisitorWithWritableScope should return only null or Unit for declarations and assignments + assert result == null || JetStandardClasses.isUnit(result); + result = JetStandardClasses.getUnitType(); + } + } } } else { result = blockLevelVisitor.getType(statementExpression, newContext); - if (coercionStrategyForLastExpression == CoercionStrategy.COERCION_TO_UNIT && result == null) { - result = JetStandardClasses.getUnitType(); - } } DataFlowInfo newDataFlowInfo = blockLevelVisitor.getResultingDataFlowInfo(); @@ -1023,8 +1042,8 @@ public class JetTypeInferrer { if (functionTypeExpected) { JetType expectedReturnType = JetStandardClasses.getReturnType(expectedType); - functionDescriptor.setReturnType(expectedReturnType); if (JetStandardClasses.isUnit(expectedReturnType)) { + functionDescriptor.setReturnType(expectedReturnType); return context.services.checkType(JetStandardClasses.getFunctionType(Collections.emptyList(), effectiveReceiverType, parameterTypes, expectedReturnType), expression, context); } @@ -2335,10 +2354,10 @@ public class JetTypeInferrer { result = getTypeForBinaryCall(context.scope, binaryOperationNames.get(operationType), context, expression); } else if (operationType == JetTokens.EQ) { - result = visitAssignment(expression, context); + result = visitAssignment(expression, contextWithExpectedType); } else if (assignmentOperationNames.containsKey(operationType)) { - result = visitAssignmentOperation(expression, context); + result = visitAssignmentOperation(expression, contextWithExpectedType); } else if (comparisonOperations.contains(operationType)) { JetType compareToReturnType = getTypeForBinaryCall(context.scope, "compareTo", context, expression); @@ -2652,7 +2671,7 @@ public class JetTypeInferrer { PropertyDescriptor propertyDescriptor = context.classDescriptorResolver.resolveObjectDeclarationAsPropertyDescriptor(scope.getContainingDeclaration(), declaration, classDescriptor); scope.addVariableDescriptor(propertyDescriptor); } - return null; + return checkExpectedType(declaration, context); } @Override @@ -2688,7 +2707,7 @@ public class JetTypeInferrer { } scope.addVariableDescriptor(propertyDescriptor); - return null; + return checkExpectedType(property, context); } @Override @@ -2696,7 +2715,7 @@ public class JetTypeInferrer { FunctionDescriptorImpl functionDescriptor = context.classDescriptorResolver.resolveFunctionDescriptor(scope.getContainingDeclaration(), scope, function); scope.addFunctionDescriptor(functionDescriptor); context.services.checkFunctionReturnType(context.scope, function, functionDescriptor, context.dataFlowInfo); - return null; + return checkExpectedType(function, context); } @Override @@ -2711,7 +2730,7 @@ public class JetTypeInferrer { @Override public JetType visitDeclaration(JetDeclaration dcl, TypeInferenceContext context) { - return visitJetElement(dcl, context); + return checkExpectedType(dcl, context); } @Override @@ -2733,6 +2752,17 @@ public class JetTypeInferrer { else { temporaryBindingTrace.commit(); } + return checkExpectedType(expression, context); + } + + @Nullable + private JetType checkExpectedType(JetExpression expression, TypeInferenceContext context) { + if (context.expectedType != NO_EXPECTED_TYPE) { + if (JetStandardClasses.isUnit(context.expectedType)) { + return JetStandardClasses.getUnitType(); + } + context.trace.report(EXPECTED_TYPE_MISMATCH.on(expression, context.expectedType)); + } return null; } @@ -2765,7 +2795,7 @@ public class JetTypeInferrer { } } } - return null; + return checkExpectedType(expression, context); } private JetType resolveArrayAccessToLValue(JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide, JetSimpleNameExpression operationSign, TypeInferenceContext context) { diff --git a/idea/testData/checkerWithErrorTypes/full/FunctionReturnTypes.jet b/idea/testData/checkerWithErrorTypes/full/FunctionReturnTypes.jet index bd049b81d25..646a38f5b89 100644 --- a/idea/testData/checkerWithErrorTypes/full/FunctionReturnTypes.jet +++ b/idea/testData/checkerWithErrorTypes/full/FunctionReturnTypes.jet @@ -168,4 +168,42 @@ fun f(): Int = if (1 < 2) 1 else returnNothing() public fun f() = 1 class B() { protected fun f() = "ss" +} + +fun testFunctionLiterals() { + val endsWithVarDeclaration : fun() : Boolean = { + val x = 2 + } + + val endsWithAssignment = { () : Int => + val x = 1 + x = 333 + } + + val endsWithReAssignment = { () : Int => + val x = 1 + x += 333 + } + + val endsWithFunDeclaration : fun() : String = { + val x = 1 + x = 333 + fun meow() : Unit {} + } + + val endsWithObjectDeclaration : fun() : Int = { + val x = 1 + x = 333 + object A {} + } + + val expectedUnitReturnType1 = { () : Unit => + val x = 1 + } + + val expectedUnitReturnType2 = { () : Unit => + fun meow() : Unit {} + object A {} + } + } \ No newline at end of file diff --git a/idea/testData/codegen/regressions/kt343.jet b/idea/testData/codegen/regressions/kt343.jet index 36b922c3f51..49a8dc9c487 100644 --- a/idea/testData/codegen/regressions/kt343.jet +++ b/idea/testData/codegen/regressions/kt343.jet @@ -1,5 +1,9 @@ import java.util.ArrayList +fun launch(f : fun() : Unit) { + f() +} + fun box(): String { val list = ArrayList() val foo : fun() : Unit = { @@ -7,10 +11,14 @@ fun box(): String { } foo() + launch({ + list.add(3) + }) + val bar = { val x = 1 //second exception } bar() - return if (list.get(0) == 2) "OK" else "fail" + return if (list.size() == 2 && list.get(0) == 2 && list.get(1) == 3) "OK" else "fail" } \ No newline at end of file From 240ed30c2f3d47ca37cfa3750ca258772720757b Mon Sep 17 00:00:00 2001 From: svtk Date: Tue, 11 Oct 2011 18:02:55 +0400 Subject: [PATCH 10/14] Calls to flowInformationProvider were removed from JetTypeInferrer --- .../jet/lang/JetSemanticServices.java | 4 +- .../jet/lang/cfg/JetControlFlowProcessor.java | 6 +- .../jet/lang/resolve/AnnotationResolver.java | 2 +- .../jet/lang/resolve/BodyResolver.java | 24 +- .../lang/resolve/ClassDescriptorResolver.java | 8 +- .../jet/lang/resolve/ControlFlowAnalyzer.java | 133 +++++++++ .../jet/lang/resolve/TopDownAnalyzer.java | 1 + .../lang/resolve/TypeHierarchyResolver.java | 4 +- .../jet/lang/types/JetTypeInferrer.java | 262 +++++++++++++----- .../jetbrains/jet/resolve/JetResolveTest.java | 2 +- .../jet/types/JetTypeCheckerTest.java | 6 +- 11 files changed, 349 insertions(+), 103 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/JetSemanticServices.java b/compiler/frontend/src/org/jetbrains/jet/lang/JetSemanticServices.java index 6d94973a3d4..6b5517ace57 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/JetSemanticServices.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/JetSemanticServices.java @@ -44,8 +44,8 @@ public class JetSemanticServices { } @NotNull - public JetTypeInferrer.Services getTypeInferrerServices(@NotNull BindingTrace trace, @NotNull JetFlowInformationProvider flowInformationProvider) { - return new JetTypeInferrer(flowInformationProvider, this).getServices(trace); + public JetTypeInferrer.Services getTypeInferrerServices(@NotNull BindingTrace trace) { + return new JetTypeInferrer(this).getServices(trace); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 95b3aa92012..7c49cf6c627 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -76,17 +76,17 @@ public class JetControlFlowProcessor { Stack stack = labeledElements.get(labelName); if (stack == null || stack.isEmpty()) { if (reportUnresolved) { - trace.report(UNRESOLVED_REFERENCE.on(labelExpression)); +// trace.report(UNRESOLVED_REFERENCE.on(labelExpression)); } return null; } else if (stack.size() > 1) { // trace.getErrorHandler().genericWarning(labelExpression.getNode(), "There is more than one label with such a name in this scope"); - trace.report(LABEL_NAME_CLASH.on(labelExpression)); +// trace.report(LABEL_NAME_CLASH.on(labelExpression)); } JetElement result = stack.peek(); - trace.record(BindingContext.LABEL_TARGET, labelExpression, result); +// trace.record(BindingContext.LABEL_TARGET, labelExpression, result); return result; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java index f00643ae6cb..9f08e5871c6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java @@ -37,7 +37,7 @@ public class AnnotationResolver { this.trace = trace; // this.typeInferrer = new JetTypeInferrer(JetFlowInformationProvider.THROW_EXCEPTION, semanticServices); // this.services = typeInferrer.getServices(this.trace); - this.callResolver = new CallResolver(semanticServices, new JetTypeInferrer(JetFlowInformationProvider.THROW_EXCEPTION, semanticServices), DataFlowInfo.getEmpty()); + this.callResolver = new CallResolver(semanticServices, new JetTypeInferrer(semanticServices), DataFlowInfo.getEmpty()); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java index 4ee7c5c2fa7..b915bec7921 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -125,7 +125,7 @@ public class BodyResolver { final JetScope scopeForConstructor = primaryConstructor == null ? null : getInnerScopeForConstructor(primaryConstructor, descriptor.getScopeForMemberResolution(), true); - final JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors, JetFlowInformationProvider.NONE); // TODO : flow + final JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors); // TODO : flow final Map supertypes = Maps.newLinkedHashMap(); JetVisitorVoid visitor = new JetVisitorVoid() { @@ -290,7 +290,7 @@ public class BodyResolver { ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); assert primaryConstructor != null; final JetScope scopeForConstructor = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getScopeForMemberResolution(), true); - JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(createFieldAssignTrackingTrace(), JetFlowInformationProvider.NONE); // TODO : flow + JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(createFieldAssignTrackingTrace()); // TODO : flow for (JetClassInitializer anonymousInitializer : anonymousInitializers) { typeInferrer.getType(scopeForConstructor, anonymousInitializer.getBody(), NO_EXPECTED_TYPE); } @@ -316,7 +316,7 @@ public class BodyResolver { private void resolveSecondaryConstructorBody(JetConstructor declaration, final ConstructorDescriptor descriptor, final JetScope declaringScope) { final JetScope functionInnerScope = getInnerScopeForConstructor(descriptor, declaringScope, false); - final JetTypeInferrer.Services typeInferrerForInitializers = context.getSemanticServices().getTypeInferrerServices(traceForConstructors, JetFlowInformationProvider.NONE); + final JetTypeInferrer.Services typeInferrerForInitializers = context.getSemanticServices().getTypeInferrerServices(traceForConstructors); JetClass containingClass = PsiTreeUtil.getParentOfType(declaration, JetClass.class); assert containingClass != null : "This must be guaranteed by the parser"; @@ -377,11 +377,11 @@ public class BodyResolver { } JetExpression bodyExpression = declaration.getBodyExpression(); if (bodyExpression != null) { - context.getClassDescriptorResolver().computeFlowData(declaration, bodyExpression); - JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(declaration, bodyExpression); - JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors, flowInformationProvider); + //context.getClassDescriptorResolver().computeFlowData(declaration, bodyExpression); + //JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(declaration, bodyExpression); + JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors); - typeInferrer.checkFunctionReturnType(functionInnerScope, declaration, JetStandardClasses.getUnitType()); + typeInferrer.checkFunctionReturnType(functionInnerScope, declaration, descriptor, JetStandardClasses.getUnitType()); } } @@ -516,8 +516,8 @@ public class BodyResolver { } private void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) { - JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(property, initializer); // TODO : flow JET-15 - JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors, flowInformationProvider); + //JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(property, initializer); // TODO : flow JET-15 + JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors); JetType type = typeInferrer.getType(getPropertyDeclarationInnerScope(scope, propertyDescriptor), initializer, NO_EXPECTED_TYPE); JetType expectedType = propertyDescriptor.getInType(); @@ -552,13 +552,13 @@ public class BodyResolver { JetExpression bodyExpression = function.getBodyExpression(); if (bodyExpression != null) { - JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(function.asElement(), bodyExpression); - JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace, flowInformationProvider); + //JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(function.asElement(), bodyExpression); + JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace); typeInferrer.checkFunctionReturnType(declaringScope, function, functionDescriptor); } - JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace, JetFlowInformationProvider.THROW_EXCEPTION); + JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace); List valueParameters = function.getValueParameters(); for (int i = 0; i < valueParameters.size(); i++) { ValueParameterDescriptor valueParameterDescriptor = functionDescriptor.getValueParameters().get(i); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index 49f3ab24bc3..de6079ebb31 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -178,8 +178,8 @@ public class ClassDescriptorResolver { returnType = DeferredType.create(trace, new LazyValueWithDefault(ErrorUtils.createErrorType("Recursive dependency")) { @Override protected JetType compute() { - JetFlowInformationProvider flowInformationProvider = computeFlowData(function, bodyExpression); - return semanticServices.getTypeInferrerServices(trace, flowInformationProvider).inferFunctionReturnType(scope, function, functionDescriptor); + //JetFlowInformationProvider flowInformationProvider = computeFlowData(function, bodyExpression); + return semanticServices.getTypeInferrerServices(trace).inferFunctionReturnType(scope, function, functionDescriptor); } }); } @@ -537,8 +537,8 @@ public class ClassDescriptorResolver { LazyValue lazyValue = new LazyValueWithDefault(ErrorUtils.createErrorType("Recursive dependency")) { @Override protected JetType compute() { - JetFlowInformationProvider flowInformationProvider = computeFlowData(property, initializer); - return semanticServices.getTypeInferrerServices(trace, flowInformationProvider).safeGetType(scope, initializer, JetTypeInferrer.NO_EXPECTED_TYPE); + //JetFlowInformationProvider flowInformationProvider = computeFlowData(property, initializer); + return semanticServices.getTypeInferrerServices(trace).safeGetType(scope, initializer, JetTypeInferrer.NO_EXPECTED_TYPE); } }; if (allowDeferred) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java new file mode 100644 index 00000000000..9e85eadfd73 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java @@ -0,0 +1,133 @@ +package org.jetbrains.jet.lang.resolve; + +import com.google.common.collect.Lists; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; +import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptorImpl; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.types.JetStandardClasses; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.JetTypeInferrer; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.jetbrains.jet.lang.diagnostics.Errors.*; +import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE; + +/** + * @author svtk + */ +public class ControlFlowAnalyzer { + private TopDownAnalysisContext context; + private JetTypeInferrer.Services typeInferrer; + + public ControlFlowAnalyzer(TopDownAnalysisContext context) { + this.context = context; + typeInferrer = context.getSemanticServices().getTypeInferrerServices(context.getTrace()); + } + + public void process() { + for (Map.Entry entry : context.getFunctions().entrySet()) { + JetNamedFunction function = entry.getKey(); + FunctionDescriptorImpl functionDescriptor = entry.getValue(); + + final JetType expectedReturnType = !function.hasBlockBody() && !function.hasDeclaredReturnType() ? NO_EXPECTED_TYPE : functionDescriptor.getReturnType(); + checkFunction(function, functionDescriptor, expectedReturnType); + } + + for (Map.Entry entry : this.context.getConstructors().entrySet()) { + JetDeclaration declaration = entry.getKey(); + assert declaration instanceof JetConstructor; + JetConstructor constructor = (JetConstructor) declaration; + ConstructorDescriptor descriptor = entry.getValue(); + + checkFunction(constructor, descriptor, JetStandardClasses.getUnitType()); + } + + for (JetProperty property : context.getProperties().keySet()) { + checkProperty(property); + } + } + + private void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor, final @NotNull JetType expectedReturnType) { + JetExpression bodyExpression = function.getBodyExpression(); + if (bodyExpression == null) return; + + JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData((JetElement)function, bodyExpression); + + final boolean blockBody = function.hasBlockBody(); + List unreachableElements = Lists.newArrayList(); + flowInformationProvider.collectUnreachableExpressions(function.asElement(), unreachableElements); + + // This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well + final Set rootUnreachableElements = JetPsiUtil.findRootExpressions(unreachableElements); + + for (JetElement element : rootUnreachableElements) { + context.getTrace().report(UNREACHABLE_CODE.on(element)); + } + + List returnedExpressions = Lists.newArrayList(); + flowInformationProvider.collectReturnExpressions(function.asElement(), returnedExpressions); + + boolean nothingReturned = returnedExpressions.isEmpty(); + + returnedExpressions.remove(function); // This will be the only "expression" if the body is empty + + final JetScope scope = this.context.getDeclaringScopes().get(function); + + if (expectedReturnType != NO_EXPECTED_TYPE && !JetStandardClasses.isUnit(expectedReturnType) && returnedExpressions.isEmpty() && !nothingReturned) { + context.getTrace().report(RETURN_TYPE_MISMATCH.on(bodyExpression, expectedReturnType)); + } + + for (JetExpression returnedExpression : returnedExpressions) { + returnedExpression.accept(new JetVisitorVoid() { + @Override + public void visitReturnExpression(JetReturnExpression expression) { + if (!blockBody) { + context.getTrace().report(RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY.on(expression)); + } + } + + @Override + public void visitExpression(JetExpression expression) { + if (blockBody && expectedReturnType != NO_EXPECTED_TYPE && !JetStandardClasses.isUnit(expectedReturnType) && !rootUnreachableElements.contains(expression)) { + JetType type = typeInferrer.getType(scope, expression, expectedReturnType); + if (type == null || !JetStandardClasses.isNothing(type)) { + context.getTrace().report(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY.on(expression)); + } + } + } + }); + } + markDominatedExpressionsAsUnreachable(bodyExpression, scope, expectedReturnType, flowInformationProvider); + } + + private void markDominatedExpressionsAsUnreachable(JetExpression expression, JetScope scope, JetType expectedReturnType, JetFlowInformationProvider flowInformationProvider) { + JetType type = typeInferrer.getType(scope, expression, expectedReturnType); + if (type == null || !JetStandardClasses.isNothing(type) || type.isNullable()) { + return; + } + + List dominated = new ArrayList(); + flowInformationProvider.collectDominatedExpressions(expression, dominated); + Set rootExpressions = JetPsiUtil.findRootExpressions(dominated); + for (JetElement rootExpression : rootExpressions) { + context.getTrace().report(UNREACHABLE_BECAUSE_OF_NOTHING.on(rootExpression, expression.getText())); + } + } + + + private void checkProperty(JetProperty property) { + JetExpression initializer = property.getInitializer(); + if (initializer == null) return; + JetScope scope = this.context.getDeclaringScopes().get(property); + JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(property, initializer); + markDominatedExpressionsAsUnreachable(initializer, scope, NO_EXPECTED_TYPE, flowInformationProvider); + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 42762dd3c5b..085f89bb0f1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -69,6 +69,7 @@ public class TopDownAnalyzer { new OverrideResolver(context).process(); new BodyResolver(context).resolveBehaviorDeclarationBodies(); new DeclarationsChecker(context).process(); + new ControlFlowAnalyzer(context).process(); } public static void processStandardLibraryNamespace( diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java index 1a5d519e22c..5958a403d7e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java @@ -218,7 +218,7 @@ public class TypeHierarchyResolver { if (importDirective.isAllUnder()) { JetExpression importedReference = importDirective.getImportedReference(); if (importedReference != null) { - JetTypeInferrer.Services typeInferrerServices = context.getSemanticServices().getTypeInferrerServices(context.getTrace(), JetFlowInformationProvider.THROW_EXCEPTION); + JetTypeInferrer.Services typeInferrerServices = context.getSemanticServices().getTypeInferrerServices(context.getTrace()); JetType type = typeInferrerServices.getTypeWithNamespaces(namespaceScope, importedReference); if (type != null) { namespaceScope.importScope(type.getMemberScope()); @@ -232,7 +232,7 @@ public class TypeHierarchyResolver { JetExpression importedReference = importDirective.getImportedReference(); if (importedReference instanceof JetDotQualifiedExpression) { JetDotQualifiedExpression reference = (JetDotQualifiedExpression) importedReference; - JetType type = context.getSemanticServices().getTypeInferrerServices(context.getTrace(), JetFlowInformationProvider.THROW_EXCEPTION).getTypeWithNamespaces(namespaceScope, reference.getReceiverExpression()); + JetType type = context.getSemanticServices().getTypeInferrerServices(context.getTrace()).getTypeWithNamespaces(namespaceScope, reference.getReceiverExpression()); JetExpression selectorExpression = reference.getSelectorExpression(); if (selectorExpression != null) { referenceExpression = (JetSimpleNameExpression) selectorExpression; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 542f9aae729..cec4b09de34 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -12,7 +12,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; import org.jetbrains.jet.lang.JetSemanticServices; -import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.diagnostics.Diagnostic; @@ -160,14 +159,16 @@ public class JetTypeInferrer { .build(); private final JetSemanticServices semanticServices; - private final JetFlowInformationProvider flowInformationProvider; +// private final JetFlowInformationProvider flowInformationProvider; private final Map patternsToDataFlowInfo = Maps.newHashMap(); private final Map> patternsToBoundVariableLists = Maps.newHashMap(); + + private final LabelsResolver labelsResolver = new LabelsResolver(); - public JetTypeInferrer(@NotNull JetFlowInformationProvider flowInformationProvider, @NotNull JetSemanticServices semanticServices) { + public JetTypeInferrer(@NotNull JetSemanticServices semanticServices) { this.semanticServices = semanticServices; - this.flowInformationProvider = flowInformationProvider; +// this.flowInformationProvider = flowInformationProvider; } public Services getServices(@NotNull BindingTrace trace) { @@ -254,7 +255,7 @@ public class JetTypeInferrer { expectedReturnType = NO_EXPECTED_TYPE; } JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace); - checkFunctionReturnType(functionInnerScope, function, expectedReturnType, dataFlowInfo); + checkFunctionReturnType(functionInnerScope, function, functionDescriptor, expectedReturnType, dataFlowInfo); // Map typeMap = collectReturnedExpressionsWithTypes(outerScope, function, functionDescriptor, expectedReturnType); // if (typeMap.isEmpty()) { // return; // The function returns Nothing @@ -288,11 +289,11 @@ public class JetTypeInferrer { // } } - public void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, @NotNull final JetType expectedReturnType) { - checkFunctionReturnType(functionInnerScope, function, expectedReturnType, DataFlowInfo.getEmpty()); + public void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, FunctionDescriptor functionDescriptor, @NotNull final JetType expectedReturnType) { + checkFunctionReturnType(functionInnerScope, function, functionDescriptor, expectedReturnType, DataFlowInfo.getEmpty()); } - private void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, @NotNull final JetType expectedReturnType, @NotNull DataFlowInfo dataFlowInfo) { + private void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, FunctionDescriptor functionDescriptor, @NotNull final JetType expectedReturnType, @NotNull DataFlowInfo dataFlowInfo) { JetExpression bodyExpression = function.getBodyExpression(); assert bodyExpression != null; @@ -310,56 +311,62 @@ public class JetTypeInferrer { typeInferrerVisitor.getType(bodyExpression, context); } - List unreachableElements = Lists.newArrayList(); - flowInformationProvider.collectUnreachableExpressions(function.asElement(), unreachableElements); +// List unreachableElements = Lists.newArrayList(); +// flowInformationProvider.collectUnreachableExpressions(function.asElement(), unreachableElements); // This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well - final Set rootUnreachableElements = JetPsiUtil.findRootExpressions(unreachableElements); +// final Set rootUnreachableElements = JetPsiUtil.findRootExpressions(unreachableElements); // TODO : (return 1) || (return 2) -- only || and right of it is unreachable // TODO : try {return 1} finally {return 2}. Currently 'return 1' is reported as unreachable, // though it'd better be reported more specifically - for (JetElement element : rootUnreachableElements) { -// trace.getErrorHandler().genericError(element.getNode(), "Unreachable code"); - trace.report(UNREACHABLE_CODE.on(element)); - } +// for (JetElement element : rootUnreachableElements) { +// //trace.report(UNREACHABLE_CODE.on(element)); +// } - List returnedExpressions = Lists.newArrayList(); - flowInformationProvider.collectReturnExpressions(function.asElement(), returnedExpressions); +// List returnedExpressions = Lists.newArrayList(); +// flowInformationProvider.collectReturnExpressions(function.asElement(), returnedExpressions); - boolean nothingReturned = returnedExpressions.isEmpty(); +// boolean nothingReturned = returnedExpressions.isEmpty(); - returnedExpressions.remove(function); // This will be the only "expression" if the body is empty + //returnedExpressions.remove(function); // This will be the only "expression" if the body is empty +// Map typeMap = collectReturnedExpressionsWithTypes(trace, functionInnerScope, function, functionDescriptor); +// Set returnedExpressions = typeMap.keySet(); +// +// +// if (expectedReturnType != NO_EXPECTED_TYPE && !JetStandardClasses.isUnit(expectedReturnType) && returnedExpressions.isEmpty()) { +// trace.report(RETURN_TYPE_MISMATCH.on(bodyExpression, expectedReturnType)); +// } - if (expectedReturnType != NO_EXPECTED_TYPE && !JetStandardClasses.isUnit(expectedReturnType) && returnedExpressions.isEmpty() && !nothingReturned) { -// trace.getErrorHandler().genericError(bodyExpression.getNode(), "This function must return a value of type " + expectedReturnType); - trace.report(RETURN_TYPE_MISMATCH.on(bodyExpression, expectedReturnType)); - } - - for (JetExpression returnedExpression : returnedExpressions) { - returnedExpression.accept(new JetVisitorVoid() { - @Override - public void visitReturnExpression(JetReturnExpression expression) { - if (!blockBody) { -// trace.getErrorHandler().genericError(expression.getNode(), "Returns are not allowed for functions with expression body. Use block body in '{...}'"); - trace.report(RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY.on(expression)); - } - } - - @Override - public void visitExpression(JetExpression expression) { - if (blockBody && !JetStandardClasses.isUnit(expectedReturnType) && !rootUnreachableElements.contains(expression)) { - //TODO move to pseudocode - JetType type = typeInferrerVisitor.getType(expression, context.replaceExpectedType(NO_EXPECTED_TYPE)); - if (type == null || !JetStandardClasses.isNothing(type)) { -// trace.getErrorHandler().genericError(expression.getNode(), "A 'return' expression required in a function with a block body ('{...}')"); - trace.report(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY.on(expression)); - } - } - } - }); - } +// if (expectedReturnType != NO_EXPECTED_TYPE && !JetStandardClasses.isUnit(expectedReturnType) && returnedExpressions.isEmpty() && !nothingReturned) { +//// trace.getErrorHandler().genericError(bodyExpression.getNode(), "This function must return a value of type " + expectedReturnType); +// trace.report(RETURN_TYPE_MISMATCH.on(bodyExpression, expectedReturnType)); +// } +// +// for (JetExpression returnedExpression : returnedExpressions) { +// returnedExpression.accept(new JetVisitorVoid() { +// @Override +// public void visitReturnExpression(JetReturnExpression expression) { +// if (!blockBody) { +//// trace.getErrorHandler().genericError(expression.getNode(), "Returns are not allowed for functions with expression body. Use block body in '{...}'"); +// trace.report(RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY.on(expression)); +// } +// } +// +// @Override +// public void visitExpression(JetExpression expression) { +// if (blockBody && !JetStandardClasses.isUnit(expectedReturnType) && !rootUnreachableElements.contains(expression)) { +// //TODO move to pseudocode +// JetType type = typeInferrerVisitor.getType(expression, context.replaceExpectedType(NO_EXPECTED_TYPE)); +// if (type == null || !JetStandardClasses.isNothing(type)) { +//// trace.getErrorHandler().genericError(expression.getNode(), "A 'return' expression required in a function with a block body ('{...}')"); +// trace.report(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY.on(expression)); +// } +// } +// } +// }); +// } } @Nullable @@ -376,14 +383,14 @@ public class JetTypeInferrer { @NotNull public JetType inferFunctionReturnType(@NotNull JetScope outerScope, JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) { - Map typeMap = collectReturnedExpressionsWithTypes(trace, outerScope, function, functionDescriptor); + Map typeMap = collectReturnedExpressionsWithTypes(trace, outerScope, function, functionDescriptor); Collection types = typeMap.values(); return types.isEmpty() ? JetStandardClasses.getNothingType() : semanticServices.getTypeChecker().commonSupertype(types); } - private Map collectReturnedExpressionsWithTypes( + private Map collectReturnedExpressionsWithTypes( @NotNull BindingTrace trace, JetScope outerScope, JetDeclarationWithBody function, @@ -392,10 +399,20 @@ public class JetTypeInferrer { assert bodyExpression != null; JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace); typeInferrerVisitor.getType(bodyExpression, newContext(trace, functionInnerScope, DataFlowInfo.getEmpty(), NO_EXPECTED_TYPE, FORBIDDEN)); - Collection returnedExpressions = new ArrayList(); - Collection elementsReturningUnit = new ArrayList(); - flowInformationProvider.collectReturnedInformation(function.asElement(), returnedExpressions, elementsReturningUnit); - Map typeMap = new HashMap(); + //todo function literals + final Collection returnedExpressions = new ArrayList(); + if (function.hasBlockBody()) { + bodyExpression.accept(new JetTreeVisitorVoid() { + @Override + public void visitReturnExpression(JetReturnExpression expression) { + returnedExpressions.add(expression); + } + }); + } + else { + returnedExpressions.add(bodyExpression); + } + Map typeMap = new HashMap(); for (JetExpression returnedExpression : returnedExpressions) { JetType cachedType = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, returnedExpression); trace.record(STATEMENT, returnedExpression, false); @@ -403,9 +420,6 @@ public class JetTypeInferrer { typeMap.put(returnedExpression, cachedType); } } - for (JetElement jetElement : elementsReturningUnit) { - typeMap.put(jetElement, JetStandardClasses.getUnitType()); - } return typeMap; } @@ -718,7 +732,6 @@ public class JetTypeInferrer { } private class TypeInferrerVisitor extends JetVisitor { - protected DataFlowInfo resultDataFlowInfo; @Nullable @@ -767,10 +780,11 @@ public class JetTypeInferrer { } if (result != null) { context.trace.record(BindingContext.EXPRESSION_TYPE, expression, result); - if (JetStandardClasses.isNothing(result) && !result.isNullable()) { - markDominatedExpressionsAsUnreachable(expression, context); - } +// if (JetStandardClasses.isNothing(result) && !result.isNullable()) { +// markDominatedExpressionsAsUnreachable(expression, context); +// } } +// } } catch (ReenteringLazyValueComputationException e) { // context.trace.getErrorHandler().genericError(expression.getNode(), "Type checking has run into a recursive problem"); // TODO : message @@ -798,16 +812,16 @@ public class JetTypeInferrer { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - private void markDominatedExpressionsAsUnreachable(JetExpression expression, TypeInferenceContext context) { - List dominated = new ArrayList(); - flowInformationProvider.collectDominatedExpressions(expression, dominated); - Set rootExpressions = JetPsiUtil.findRootExpressions(dominated); - for (JetElement rootExpression : rootExpressions) { -// context.trace.getErrorHandler().genericError(rootExpression.getNode(), -// "This code is unreachable, because '" + expression.getText() + "' never terminates normally"); - context.trace.report(UNREACHABLE_BECAUSE_OF_NOTHING.on(rootExpression, expression.getText())); - } - } +// private void markDominatedExpressionsAsUnreachable(JetExpression expression, TypeInferenceContext context) { +// List dominated = new ArrayList(); +// flowInformationProvider.collectDominatedExpressions(expression, dominated); +// Set rootExpressions = JetPsiUtil.findRootExpressions(dominated); +// for (JetElement rootExpression : rootExpressions) { +//// context.trace.getErrorHandler().genericError(rootExpression.getNode(), +//// "This code is unreachable, because '" + expression.getText() + "' never terminates normally"); +// context.trace.report(UNREACHABLE_BECAUSE_OF_NOTHING.on(rootExpression, expression.getText())); +// } +// } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1029,7 +1043,7 @@ public class JetTypeInferrer { JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef(); if (returnTypeRef != null) { returnType = context.typeResolver.resolveType(context.scope, returnTypeRef); - context.services.checkFunctionReturnType(functionInnerScope, expression, returnType, context.dataFlowInfo); + context.services.checkFunctionReturnType(functionInnerScope, expression, functionDescriptor, returnType, context.dataFlowInfo); } else { if (functionTypeExpected) { @@ -1139,6 +1153,12 @@ public class JetTypeInferrer { @Override public JetType visitReturnExpression(JetReturnExpression expression, TypeInferenceContext context) { + JetSimpleNameExpression labelElement = expression.getTargetLabel(); + if (labelElement != null) { + String labelName = expression.getLabelName(); + assert labelName != null; + labelsResolver.resolveLabel(labelName, labelElement, true, context); + } if (context.expectedReturnType == FORBIDDEN) { // context.trace.getErrorHandler().genericError(expression.getNode(), "'return' is not allowed here"); context.trace.report(RETURN_NOT_ALLOWED.on(expression)); @@ -1161,11 +1181,13 @@ public class JetTypeInferrer { @Override public JetType visitBreakExpression(JetBreakExpression expression, TypeInferenceContext context) { + labelsResolver.resolveCorrespondingLoopLabel(expression, context); return context.services.checkType(JetStandardClasses.getNothingType(), expression, context); } @Override public JetType visitContinueExpression(JetContinueExpression expression, TypeInferenceContext context) { + labelsResolver.resolveCorrespondingLoopLabel(expression, context); return context.services.checkType(JetStandardClasses.getNothingType(), expression, context); } @@ -1306,6 +1328,8 @@ public class JetTypeInferrer { context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor); } else if (size == 0) { + //todo (first we put to the context, then get from it) + labelsResolver.resolveLabel(labelName, targetLabel, false, context); // This uses the info written by the control flow processor PsiElement psiElement = BindingContextUtils.resolveToDeclarationPsiElement(context.trace.getBindingContext(), targetLabel); if (psiElement instanceof JetFunctionLiteralExpression) { @@ -1860,19 +1884,21 @@ public class JetTypeInferrer { DataFlowInfo conditionInfo = condition == null ? context.dataFlowInfo : extractDataFlowInfoFromCondition(condition, true, scopeToExtend, context); getTypeWithNewScopeAndDataFlowInfo(scopeToExtend, body, conditionInfo, context); } - if (!isBreakable(expression)) { + if (!containsBreak(expression)) { // resultScope = newWritableScopeImpl(); resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false, null, context); } return context.services.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType); } - private boolean isBreakable(JetLoopExpression expression) { + private boolean containsBreak(JetLoopExpression expression) { final boolean[] result = new boolean[1]; result[0] = false; expression.accept(new JetTreeVisitorVoid() { @Override public void visitBreakExpression(JetBreakExpression expression) { + //todo get exact loop for this break, compare to expression + //expression.getLabeledExpression() result[0] = true; } }); @@ -1903,7 +1929,7 @@ public class JetTypeInferrer { } JetExpression condition = expression.getCondition(); checkCondition(conditionScope, condition, context); - if (!isBreakable(expression)) { + if (!containsBreak(expression)) { // resultScope = newWritableScopeImpl(); resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false, null, context); } @@ -2289,8 +2315,13 @@ public class JetTypeInferrer { if (baseExpression == null) return null; JetSimpleNameExpression operationSign = expression.getOperationSign(); if (JetTokens.LABELS.contains(operationSign.getReferencedNameElementType())) { + String referencedName = operationSign.getReferencedName(); + referencedName = referencedName == null ? " " : referencedName; + labelsResolver.enterLabeledElement(referencedName.substring(1), baseExpression); // TODO : Some processing for the label? - return context.services.checkType(getType(baseExpression, context.replaceExpectedReturnType(context.expectedType)), expression, context); + JetType type = context.services.checkType(getType(baseExpression, context.replaceExpectedReturnType(context.expectedType)), expression, context); + labelsResolver.exitLabeledElement(baseExpression); + return type; } IElementType operationType = operationSign.getReferencedNameElementType(); String name = unaryOperationNames.get(operationType); @@ -2331,6 +2362,7 @@ public class JetTypeInferrer { else { result = returnType; } + return context.services.checkType(result, expression, context); } @@ -2830,4 +2862,84 @@ public class JetTypeInferrer { return null; } } + + private class LabelsResolver { + private final Map> labeledElements = new HashMap>(); + + private void enterLabeledElement(@NotNull String labelName, @NotNull JetExpression labeledExpression) { + JetExpression deparenthesized = JetPsiUtil.deparenthesize(labeledExpression); + if (deparenthesized != null) { + Stack stack = labeledElements.get(labelName); + if (stack == null) { + stack = new Stack(); + labeledElements.put(labelName, stack); + } + stack.push(deparenthesized); + } + } + + private void exitLabeledElement(JetExpression expression) { + JetExpression deparenthesized = JetPsiUtil.deparenthesize(expression); + // TODO : really suboptimal + for (Iterator>> mapIter = labeledElements.entrySet().iterator(); mapIter.hasNext(); ) { + Map.Entry> entry = mapIter.next(); + Stack stack = entry.getValue(); + for (Iterator stackIter = stack.iterator(); stackIter.hasNext(); ) { + JetElement recorded = stackIter.next(); + if (recorded == deparenthesized) { + stackIter.remove(); + } + } + if (stack.isEmpty()) { + mapIter.remove(); + } + } + } + + private void resolveLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved, TypeInferenceContext context) { + Collection declarationsByLabel = context.scope.getDeclarationsByLabel(labelName); + int size = declarationsByLabel.size(); + + if (size == 1) { + DeclarationDescriptor declarationDescriptor = declarationsByLabel.iterator().next(); + JetElement element; + if (declarationDescriptor instanceof ClassDescriptor) { + ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; + element = (JetElement) context.trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, classDescriptor); + } + else if (declarationDescriptor instanceof FunctionDescriptor) { + FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor; + element = (JetElement) context.trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, functionDescriptor); + } + else { + throw new UnsupportedOperationException(); // TODO + } + context.trace.record(LABEL_TARGET, labelExpression, element); + return; + } + + Stack stack = labeledElements.get(labelName); + if (stack == null || stack.isEmpty()) { + if (reportUnresolved) { + context.trace.report(UNRESOLVED_REFERENCE.on(labelExpression)); + } + return; + } + else if (stack.size() > 1) { + context.trace.report(LABEL_NAME_CLASH.on(labelExpression)); + } + + JetElement result = stack.peek(); + context.trace.record(BindingContext.LABEL_TARGET, labelExpression, result); + } + + private void resolveCorrespondingLoopLabel(JetLabelQualifiedExpression expression, TypeInferenceContext context) { + String labelName = expression.getLabelName(); + if (labelName != null) { + JetSimpleNameExpression targetLabel = expression.getTargetLabel(); + assert targetLabel != null; + resolveLabel(labelName, targetLabel, true, context); + } + } + } } diff --git a/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java b/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java index 058b742d5e6..b7786c8c126 100644 --- a/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java +++ b/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java @@ -106,7 +106,7 @@ public class JetResolveTest extends ExtensibleResolveTestCase { @NotNull private FunctionDescriptor standardFunction(ClassDescriptor classDescriptor, List typeArguments, String name, JetType... parameterType) { List parameterTypeList = Arrays.asList(parameterType); - JetTypeInferrer.Services typeInferrerServices = JetSemanticServices.createSemanticServices(getProject()).getTypeInferrerServices(new BindingTraceContext(), JetFlowInformationProvider.NONE); + JetTypeInferrer.Services typeInferrerServices = JetSemanticServices.createSemanticServices(getProject()).getTypeInferrerServices(new BindingTraceContext()); OverloadResolutionResults functions = typeInferrerServices.getCallResolver().resolveExactSignature( classDescriptor.getMemberScope(typeArguments), ReceiverDescriptor.NO_RECEIVER, name, parameterTypeList); diff --git a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java index 1903d2b13f1..dd787a1cd9b 100644 --- a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java +++ b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java @@ -493,14 +493,14 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { private void assertType(String expression, JetType expectedType) { Project project = getProject(); JetExpression jetExpression = JetPsiFactory.createExpression(project, expression); - JetType type = semanticServices.getTypeInferrerServices(JetTestUtils.DUMMY_TRACE, JetFlowInformationProvider.NONE).getType(scopeWithImports, jetExpression, JetTypeInferrer.NO_EXPECTED_TYPE); + JetType type = semanticServices.getTypeInferrerServices(JetTestUtils.DUMMY_TRACE).getType(scopeWithImports, jetExpression, JetTypeInferrer.NO_EXPECTED_TYPE); assertTrue(type + " != " + expectedType, type.equals(expectedType)); } private void assertErrorType(String expression) { Project project = getProject(); JetExpression jetExpression = JetPsiFactory.createExpression(project, expression); - JetType type = semanticServices.getTypeInferrerServices(JetTestUtils.DUMMY_TRACE, JetFlowInformationProvider.NONE).safeGetType(scopeWithImports, jetExpression, JetTypeInferrer.NO_EXPECTED_TYPE); + JetType type = semanticServices.getTypeInferrerServices(JetTestUtils.DUMMY_TRACE).safeGetType(scopeWithImports, jetExpression, JetTypeInferrer.NO_EXPECTED_TYPE); assertTrue("Error type expected but " + type + " returned", ErrorUtils.isErrorType(type)); } @@ -523,7 +523,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { private void assertType(JetScope scope, String expression, String expectedTypeStr) { Project project = getProject(); JetExpression jetExpression = JetPsiFactory.createExpression(project, expression); - JetType type = semanticServices.getTypeInferrerServices(JetTestUtils.DUMMY_TRACE, JetFlowInformationProvider.NONE).getType(addImports(scope), jetExpression, JetTypeInferrer.NO_EXPECTED_TYPE); + JetType type = semanticServices.getTypeInferrerServices(JetTestUtils.DUMMY_TRACE).getType(addImports(scope), jetExpression, JetTypeInferrer.NO_EXPECTED_TYPE); JetType expectedType = expectedTypeStr == null ? null : makeType(expectedTypeStr); assertEquals(expectedType, type); } From 06a7fa1f16b92d586ad824bb12228cbfd550a1b1 Mon Sep 17 00:00:00 2001 From: svtk Date: Wed, 12 Oct 2011 15:07:11 +0400 Subject: [PATCH 11/14] Added information about 'nothing' to control flow graph --- .../jet/lang/cfg/JetControlFlowBuilder.java | 1 + .../cfg/JetControlFlowBuilderAdapter.java | 5 + .../jet/lang/cfg/JetControlFlowProcessor.java | 20 + .../lang/cfg/JetFlowInformationProvider.java | 110 +-- .../JetControlFlowInstructionsGenerator.java | 5 + .../jet/lang/diagnostics/Errors.java | 1 - .../jet/lang/psi/JetTreeVisitor.java | 796 ++++++++++++++++++ .../jet/lang/psi/JetTreeVisitorVoid.java | 728 ---------------- .../jet/lang/resolve/ControlFlowAnalyzer.java | 23 +- .../jet/lang/types/JetTypeInferrer.java | 33 +- idea/testData/cfg/ArrayAccess.instructions | 12 - idea/testData/cfg/Assignments.instructions | 53 -- idea/testData/checker/UnreachableCode.jet | 4 +- .../full/UnreachableCode.jet | 8 +- 14 files changed, 914 insertions(+), 885 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTreeVisitor.java delete mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTreeVisitorVoid.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java index 9549a4ab0f0..4658d844a4f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java @@ -25,6 +25,7 @@ public interface JetControlFlowBuilder { void jumpOnTrue(@NotNull Label label); void nondeterministicJump(Label label); // Maybe, jump to label void jumpToError(JetThrowExpression expression); + void jumpToError(JetExpression nothingExpression); // Entry/exit points Label getEntryPoint(@NotNull JetElement labelElement); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java index 6137517b40c..7d4dd4744dc 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java @@ -62,6 +62,11 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder { builder.jumpToError(expression); } + @Override + public void jumpToError(JetExpression nothingExpression) { + builder.jumpToError(nothingExpression); + } + @Override public Label getEntryPoint(@NotNull JetElement labelElement) { return builder.getEntryPoint(labelElement); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 7c49cf6c627..aa185dcee86 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -6,6 +6,8 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingTrace; +import org.jetbrains.jet.lang.types.JetStandardClasses; +import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetTypeInferrer; import org.jetbrains.jet.lexer.JetTokens; @@ -137,6 +139,12 @@ public class JetControlFlowProcessor { @Override public void visitSimpleNameExpression(JetSimpleNameExpression expression) { builder.read(expression); + if (trace.get(BindingContext.PROCESSED, expression)) { + JetType type = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression); + if (type != null && JetStandardClasses.isNothing(type)) { + builder.jumpToError(expression); + } + } } @Override @@ -522,6 +530,12 @@ public class JetControlFlowProcessor { value(selectorExpression, false); } builder.read(expression); + if (trace.get(BindingContext.PROCESSED, expression)) { + JetType type = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression); + if (type != null && JetStandardClasses.isNothing(type)) { + builder.jumpToError(expression); + } + } } private void visitCall(JetCallElement call) { @@ -547,6 +561,12 @@ public class JetControlFlowProcessor { value(expression.getCalleeExpression(), false); builder.read(expression); + if (trace.get(BindingContext.PROCESSED, expression)) { + JetType type = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression); + if (type != null && JetStandardClasses.isNothing(type)) { + builder.jumpToError(expression); + } + } } // @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index 8e27cbd262b..7430be1bed2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -11,61 +11,61 @@ import java.util.Collection; * @author abreslav */ public interface JetFlowInformationProvider { - JetFlowInformationProvider THROW_EXCEPTION = new JetFlowInformationProvider() { - @Override - public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions, @NotNull Collection elementsReturningUnit) { - throw new UnsupportedOperationException(); - } - - @Override - public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions) { - throw new UnsupportedOperationException(); - } - - @Override - public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection unreachableElements) { - throw new UnsupportedOperationException(); - } - - @Override - public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection dominated) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isBreakable(JetLoopExpression loop) { - throw new UnsupportedOperationException(); - } - - }; - - JetFlowInformationProvider NONE = new JetFlowInformationProvider() { - @Override - public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions, @NotNull Collection elementsReturningUnit) { - - } - - @Override - public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions) { - - } - - @Override - public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection unreachableElements) { - - } - - @Override - public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection dominated) { - - } - - @Override - public boolean isBreakable(JetLoopExpression loop) { - return false; - } - - }; +// JetFlowInformationProvider THROW_EXCEPTION = new JetFlowInformationProvider() { +// @Override +// public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions, @NotNull Collection elementsReturningUnit) { +// throw new UnsupportedOperationException(); +// } +// +// @Override +// public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions) { +// throw new UnsupportedOperationException(); +// } +// +// @Override +// public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection unreachableElements) { +// throw new UnsupportedOperationException(); +// } +// +// @Override +// public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection dominated) { +// throw new UnsupportedOperationException(); +// } +// +// @Override +// public boolean isBreakable(JetLoopExpression loop) { +// throw new UnsupportedOperationException(); +// } +// +// }; +// +// JetFlowInformationProvider NONE = new JetFlowInformationProvider() { +// @Override +// public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions, @NotNull Collection elementsReturningUnit) { +// +// } +// +// @Override +// public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions) { +// +// } +// +// @Override +// public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection unreachableElements) { +// +// } +// +// @Override +// public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection dominated) { +// +// } +// +// @Override +// public boolean isBreakable(JetLoopExpression loop) { +// return false; +// } +// +// }; /** * Collects expressions returned from the given subroutine and 'return;' expressions diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java index ef7ee3e76f2..0014eaa70be 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java @@ -250,6 +250,11 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd public void jumpToError(JetThrowExpression expression) { add(new UnconditionalJumpInstruction(error)); } + + @Override + public void jumpToError(JetExpression nothingExpression) { + add(new UnconditionalJumpInstruction(error)); + } @Override public void enterTryFinally(@NotNull GenerationTrigger generationTrigger) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 2f98129c988..f92959e2ef7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -144,7 +144,6 @@ public interface Errors { PsiElementOnlyDiagnosticFactory3 VIRTUAL_MEMBER_HIDDEN = PsiElementOnlyDiagnosticFactory3.create(ERROR, "''{0}'' hides ''{1}'' in class {2} and needs 'override' modifier", DescriptorRenderer.TEXT); SimpleDiagnosticFactory UNREACHABLE_CODE = SimpleDiagnosticFactory.create(ERROR, "Unreachable code"); - ParameterizedDiagnosticFactory1 UNREACHABLE_BECAUSE_OF_NOTHING = ParameterizedDiagnosticFactory1.create(ERROR, "This code is unreachable, because ''{0}'' never terminates normally"); SimpleDiagnosticFactory MANY_CLASS_OBJECTS = SimpleDiagnosticFactory.create(ERROR, "Only one class object is allowed per class"); SimpleDiagnosticFactory CLASS_OBJECT_NOT_ALLOWED = SimpleDiagnosticFactory.create(ERROR, "A class object is not allowed here"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTreeVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTreeVisitor.java new file mode 100644 index 00000000000..8b88df1f4ff --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTreeVisitor.java @@ -0,0 +1,796 @@ +package org.jetbrains.jet.lang.psi; + +import java.util.List; + +/** + * @author svtk + */ +public class JetTreeVisitor extends JetVisitor { + @Override + public Void visitNamespace(JetNamespace namespace, D data) { + List importDirectives = namespace.getImportDirectives(); + for (JetImportDirective directive : importDirectives) { + directive.visit(this, data); + } + List declarations = namespace.getDeclarations(); + for (JetDeclaration declaration : declarations) { + declaration.visit(this, data); + } + return null; + } + + @Override + public Void visitClass(JetClass klass, D data) { + List declarations = klass.getDeclarations(); + for (JetDeclaration declaration : declarations) { + declaration.visit(this, data); + } + return null; + } + + @Override + public Void visitClassObject(JetClassObject classObject, D data) { + JetObjectDeclaration objectDeclaration = classObject.getObjectDeclaration(); + if (objectDeclaration != null) { + objectDeclaration.visit(this, data); + } + return null; + } + + @Override + public Void visitConstructor(JetConstructor constructor, D data) { + visitDeclarationWithBody(constructor, data); + return null; + } + + @Override + public Void visitNamedFunction(JetNamedFunction function, D data) { + visitDeclarationWithBody(function, data); + return null; + } + + @Override + public Void visitProperty(JetProperty property, D data) { + List accessors = property.getAccessors(); + for (JetPropertyAccessor accessor : accessors) { + accessor.visit(this, data); + } + JetExpression initializer = property.getInitializer(); + if (initializer != null) { + initializer.visit(this, data); + } + return null; + } + + @Override + public Void visitTypedef(JetTypedef typedef, D data) { + return super.visitTypedef(typedef, data); + } + + @Override + public Void visitJetFile(JetFile file, D data) { + JetNamespace rootNamespace = file.getRootNamespace(); + return rootNamespace.visit(this, data); + } + + @Override + public Void visitImportDirective(JetImportDirective importDirective, D data) { + return super.visitImportDirective(importDirective, data); + } + + @Override + public Void visitClassBody(JetClassBody classBody, D data) { + List declarations = classBody.getDeclarations(); + for (JetDeclaration declaration : declarations) { + declaration.visit(this, data); + } + List secondaryConstructors = classBody.getSecondaryConstructors(); + for (JetConstructor constructor : secondaryConstructors) { + constructor.visit(this, data); + } + return null; + } + + @Override + public Void visitNamespaceBody(JetNamespaceBody body, D data) { + List declarations = body.getDeclarations(); + for (JetDeclaration declaration : declarations) { + declaration.visit(this, data); + } + return null; + } + + @Override + public Void visitModifierList(JetModifierList list, D data) { + return super.visitModifierList(list, data); + } + + @Override + public Void visitAnnotation(JetAnnotation annotation, D data) { + return super.visitAnnotation(annotation, data); + } + + @Override + public Void visitAnnotationEntry(JetAnnotationEntry annotationEntry, D data) { + return super.visitAnnotationEntry(annotationEntry, data); + } + + @Override + public Void visitTypeParameterList(JetTypeParameterList list, D data) { + List parameters = list.getParameters(); + for (JetTypeParameter parameter : parameters) { + parameter.visit(this, data); + } + return null; + } + + @Override + public Void visitTypeParameter(JetTypeParameter parameter, D data) { + return super.visitTypeParameter(parameter, data); + } + + @Override + public Void visitEnumEntry(JetEnumEntry enumEntry, D data) { + List delegationSpecifiers = enumEntry.getDelegationSpecifiers(); + for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) { + delegationSpecifier.visit(this, data); + } + JetModifierList modifierList = enumEntry.getModifierList(); + if (modifierList != null) { + modifierList.visit(this, data); + } + return null; + } + + @Override + public Void visitParameterList(JetParameterList list, D data) { + List parameters = list.getParameters(); + for (JetParameter parameter : parameters) { + parameter.visit(this, data); + } + return null; + } + + @Override + public Void visitParameter(JetParameter parameter, D data) { + return super.visitParameter(parameter, data); + } + + @Override + public Void visitDelegationSpecifierList(JetDelegationSpecifierList list, D data) { + List delegationSpecifiers = list.getDelegationSpecifiers(); + for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) { + delegationSpecifier.visit(this, data); + } + return null; + } + + @Override + public Void visitDelegationSpecifier(JetDelegationSpecifier specifier, D data) { + return super.visitDelegationSpecifier(specifier, data); + } + + @Override + public Void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier, D data) { + return super.visitDelegationByExpressionSpecifier(specifier, data); + } + + @Override + public Void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call, D data) { + return super.visitDelegationToSuperCallSpecifier(call, data); + } + + @Override + public Void visitDelegationToSuperClassSpecifier(JetDelegatorToSuperClass specifier, D data) { + return super.visitDelegationToSuperClassSpecifier(specifier, data); + } + + @Override + public Void visitDelegationToThisCall(JetDelegatorToThisCall thisCall, D data) { + return super.visitDelegationToThisCall(thisCall, data); + } + + @Override + public Void visitTypeReference(JetTypeReference typeReference, D data) { + return super.visitTypeReference(typeReference, data); + } + + @Override + public Void visitValueArgumentList(JetValueArgumentList list, D data) { + List arguments = list.getArguments(); + for (JetValueArgument argument : arguments) { + argument.visit(this, data); + } + return null; + } + + @Override + public Void visitArgument(JetValueArgument argument, D data) { + return super.visitArgument(argument, data); + } + + @Override + public Void visitLoopExpression(JetLoopExpression loopExpression, D data) { + JetExpression body = loopExpression.getBody(); + if (body != null) { + body.visit(this, data); + } + return null; + } + + @Override + public Void visitConstantExpression(JetConstantExpression expression, D data) { + return super.visitConstantExpression(expression, data); + } + + @Override + public Void visitSimpleNameExpression(JetSimpleNameExpression expression, D data) { + return super.visitSimpleNameExpression(expression, data); + } + + @Override + public Void visitReferenceExpression(JetReferenceExpression expression, D data) { + return super.visitReferenceExpression(expression, data); + } + + @Override + public Void visitTupleExpression(JetTupleExpression expression, D data) { + return super.visitTupleExpression(expression, data); + } + + @Override + public Void visitPrefixExpression(JetPrefixExpression expression, D data) { + JetExpression baseExpression = expression.getBaseExpression(); + if (baseExpression != null) { + baseExpression.visit(this, data); + } + return null; + } + + @Override + public Void visitPostfixExpression(JetPostfixExpression expression, D data) { + JetExpression baseExpression = expression.getBaseExpression(); + baseExpression.visit(this, data); + return null; + } + + @Override + public Void visitUnaryExpression(JetUnaryExpression expression, D data) { + JetExpression baseExpression = expression.getBaseExpression(); + assert baseExpression != null; + baseExpression.visit(this, data); + return null; + } + + @Override + public Void visitBinaryExpression(JetBinaryExpression expression, D data) { + JetExpression left = expression.getLeft(); + left.visit(this, data); + JetExpression right = expression.getRight(); + if (right != null) { + right.visit(this, data); + } + return super.visitBinaryExpression(expression, data); + } + + @Override + public Void visitReturnExpression(JetReturnExpression expression, D data) { + JetExpression returnedExpression = expression.getReturnedExpression(); + if (returnedExpression != null) { + returnedExpression.visit(this, data); + } + return null; + } + + @Override + public Void visitLabelQualifiedExpression(JetLabelQualifiedExpression expression, D data) { + JetExpression labeledExpression = expression.getLabeledExpression(); + if (labeledExpression != null) { + labeledExpression.visit(this, data); + } + return null; + } + + @Override + public Void visitThrowExpression(JetThrowExpression expression, D data) { + JetExpression thrownExpression = expression.getThrownExpression(); + if (thrownExpression != null) { + thrownExpression.visit(this, data); + } + return null; + } + + @Override + public Void visitBreakExpression(JetBreakExpression expression, D data) { + return super.visitBreakExpression(expression, data); + } + + @Override + public Void visitContinueExpression(JetContinueExpression expression, D data) { + return super.visitContinueExpression(expression, data); + } + + @Override + public Void visitIfExpression(JetIfExpression expression, D data) { + JetExpression condition = expression.getCondition(); + if (condition != null) { + condition.visit(this, data); + } + JetExpression then = expression.getThen(); + if (then != null) { + then.visit(this, data); + } + JetExpression anElse = expression.getElse(); + if (anElse != null) { + anElse.visit(this, data); + } + return null; + } + + @Override + public Void visitWhenExpression(JetWhenExpression expression, D data) { + List entries = expression.getEntries(); + for (JetWhenEntry entry : entries) { + entry.visit(this, data); + } + JetExpression subjectExpression = expression.getSubjectExpression(); + if (subjectExpression != null) { + subjectExpression.visit(this, data); + } + return null; + } + + @Override + public Void visitTryExpression(JetTryExpression expression, D data) { + JetBlockExpression tryBlock = expression.getTryBlock(); + tryBlock.visit(this, data); + List catchClauses = expression.getCatchClauses(); + for (JetCatchClause catchClause : catchClauses) { + catchClause.visit(this, data); + } + JetFinallySection finallyBlock = expression.getFinallyBlock(); + if (finallyBlock != null) { + finallyBlock.visit(this, data); + } + return null; + } + + @Override + public Void visitForExpression(JetForExpression expression, D data) { + JetParameter loopParameter = expression.getLoopParameter(); + if (loopParameter != null) { + loopParameter.visit(this, data); + } + JetExpression loopRange = expression.getLoopRange(); + if (loopRange != null) { + loopRange.visit(this, data); + } + visitLoopExpression(expression, data); + return null; + } + + @Override + public Void visitWhileExpression(JetWhileExpression expression, D data) { + JetExpression condition = expression.getCondition(); + if (condition != null) { + condition.visit(this, data); + } + visitLoopExpression(expression, data); + return null; + } + + @Override + public Void visitDoWhileExpression(JetDoWhileExpression expression, D data) { + JetExpression condition = expression.getCondition(); + if (condition != null) { + condition.visit(this, data); + } + visitLoopExpression(expression, data); + return null; + } + + @Override + public Void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, D data) { + JetFunctionLiteral functionLiteral = expression.getFunctionLiteral(); + functionLiteral.visit(this, data); + visitDeclarationWithBody(expression, data); + return null; + } + + @Override + public Void visitAnnotatedExpression(JetAnnotatedExpression expression, D data) { + JetExpression baseExpression = expression.getBaseExpression(); + baseExpression.visit(this, data); + return null; + } + + @Override + public Void visitCallExpression(JetCallExpression expression, D data) { + JetExpression calleeExpression = expression.getCalleeExpression(); + if (calleeExpression != null) { + calleeExpression.visit(this, data); + } + return null; + } + + @Override + public Void visitArrayAccessExpression(JetArrayAccessExpression expression, D data) { + JetExpression arrayExpression = expression.getArrayExpression(); + arrayExpression.visit(this, data); + List indexExpressions = expression.getIndexExpressions(); + for (JetExpression indexExpression : indexExpressions) { + indexExpression.visit(this, data); + } + return null; + } + + @Override + public Void visitQualifiedExpression(JetQualifiedExpression expression, D data) { + JetExpression receiver = expression.getReceiverExpression(); + receiver.visit(this, data); + JetExpression selector = expression.getSelectorExpression(); + if (selector != null) { + selector.visit(this, data); + } + return null; + } + + @Override + public Void visitHashQualifiedExpression(JetHashQualifiedExpression expression, D data) { + visitQualifiedExpression(expression, data); + return null; + } + + @Override + public Void visitDotQualifiedExpression(JetDotQualifiedExpression expression, D data) { + visitQualifiedExpression(expression, data); + return null; + } + + @Override + public Void visitPredicateExpression(JetPredicateExpression expression, D data) { + visitQualifiedExpression(expression, data); + return null; + } + + @Override + public Void visitSafeQualifiedExpression(JetSafeQualifiedExpression expression, D data) { + visitQualifiedExpression(expression, data); + return null; + } + + @Override + public Void visitObjectLiteralExpression(JetObjectLiteralExpression expression, D data) { + JetObjectDeclaration objectDeclaration = expression.getObjectDeclaration(); + objectDeclaration.visit(this, data); + return null; + } + + @Override + public Void visitRootNamespaceExpression(JetRootNamespaceExpression expression, D data) { + return super.visitRootNamespaceExpression(expression, data); + } + + @Override + public Void visitBlockExpression(JetBlockExpression expression, D data) { + List statements = expression.getStatements(); + for (JetElement statement : statements) { + statement.visit(this, data); + } + return null; + } + + @Override + public Void visitCatchSection(JetCatchClause catchClause, D data) { + JetParameter catchParameter = catchClause.getCatchParameter(); + if (catchParameter != null) { + catchParameter.visit(this, data); + } + JetExpression catchBody = catchClause.getCatchBody(); + if (catchBody != null) { + catchBody.visit(this, data); + } + return null; + } + + @Override + public Void visitFinallySection(JetFinallySection finallySection, D data) { + JetBlockExpression finalExpression = finallySection.getFinalExpression(); + finalExpression.visit(this, data); + return null; + } + + @Override + public Void visitTypeArgumentList(JetTypeArgumentList typeArgumentList, D data) { + List arguments = typeArgumentList.getArguments(); + for (JetTypeProjection argument : arguments) { + argument.visit(this, data); + } + return null; + } + + @Override + public Void visitThisExpression(JetThisExpression expression, D data) { + JetReferenceExpression thisReference = expression.getThisReference(); + thisReference.visit(this, data); + JetTypeReference superTypeQualifier = expression.getSuperTypeQualifier(); + if (superTypeQualifier != null) { + superTypeQualifier.visit(this, data); + } + visitLabelQualifiedExpression(expression, data); + return null; + } + + @Override + public Void visitParenthesizedExpression(JetParenthesizedExpression expression, D data) { + JetExpression innerExpression = expression.getExpression(); + if (innerExpression != null) { + innerExpression.visit(this, data); + } + return null; + } + + @Override + public Void visitInitializerList(JetInitializerList list, D data) { + List initializers = list.getInitializers(); + for (JetDelegationSpecifier initializer : initializers) { + initializer.visit(this, data); + } + return null; + } + + @Override + public Void visitAnonymousInitializer(JetClassInitializer initializer, D data) { + JetExpression body = initializer.getBody(); + body.visit(this, data); + return null; + } + + @Override + public Void visitPropertyAccessor(JetPropertyAccessor accessor, D data) { + visitDeclarationWithBody(accessor, data); + return null; + } + + @Override + public Void visitTypeConstraintList(JetTypeConstraintList list, D data) { + List constraints = list.getConstraints(); + for (JetTypeConstraint constraint : constraints) { + constraint.visit(this, data); + } + return null; + } + + @Override + public Void visitTypeConstraint(JetTypeConstraint constraint, D data) { + JetSimpleNameExpression subjectTypeParameterName = constraint.getSubjectTypeParameterName(); + if (subjectTypeParameterName != null) { + subjectTypeParameterName.visit(this, data); + } + return null; + } + + @Override + public Void visitUserType(JetUserType type, D data) { + return super.visitUserType(type, data); + } + + @Override + public Void visitTupleType(JetTupleType type, D data) { + return super.visitTupleType(type, data); + } + + @Override + public Void visitFunctionType(JetFunctionType type, D data) { + return super.visitFunctionType(type, data); + } + + @Override + public Void visitSelfType(JetSelfType type, D data) { + return super.visitSelfType(type, data); + } + + @Override + public Void visitBinaryWithTypeRHSExpression(JetBinaryExpressionWithTypeRHS expression, D data) { + JetExpression left = expression.getLeft(); + left.visit(this, data); + JetTypeReference right = expression.getRight(); + if (right != null) { + right.visit(this, data); + } + return null; + } + + @Override + public Void visitStringTemplateExpression(JetStringTemplateExpression expression, D data) { + JetStringTemplateEntry[] entries = expression.getEntries(); + for (JetStringTemplateEntry entry : entries) { + entry.visit(this, data); + } + return null; + } + + @Override + public Void visitNamedDeclaration(JetNamedDeclaration declaration, D data) { + return super.visitNamedDeclaration(declaration, data); + } + + @Override + public Void visitNullableType(JetNullableType nullableType, D data) { + return super.visitNullableType(nullableType, data); + } + + @Override + public Void visitTypeProjection(JetTypeProjection typeProjection, D data) { + return super.visitTypeProjection(typeProjection, data); + } + + @Override + public Void visitWhenEntry(JetWhenEntry jetWhenEntry, D data) { + JetExpression expression = jetWhenEntry.getExpression(); + if (expression != null) { + expression.visit(this, data); + } + JetWhenCondition[] conditions = jetWhenEntry.getConditions(); + for (JetWhenCondition condition : conditions) { + condition.visit(this, data); + } + return null; + } + + @Override + public Void visitIsExpression(JetIsExpression expression, D data) { + JetExpression leftHandSide = expression.getLeftHandSide(); + leftHandSide.visit(this, data); + JetSimpleNameExpression operationReference = expression.getOperationReference(); + operationReference.visit(this, data); + JetPattern pattern = expression.getPattern(); + if (pattern != null) { + pattern.visit(this, data); + } + return null; + } + + @Override + public Void visitWhenConditionCall(JetWhenConditionCall condition, D data) { + JetExpression callSuffixExpression = condition.getCallSuffixExpression(); + if (callSuffixExpression != null) { + callSuffixExpression.visit(this, data); + } + return null; + } + + @Override + public Void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition, D data) { + JetPattern pattern = condition.getPattern(); + if (pattern != null) { + pattern.visit(this, data); + } + return null; + } + + @Override + public Void visitWhenConditionInRange(JetWhenConditionInRange condition, D data) { + JetSimpleNameExpression operationReference = condition.getOperationReference(); + operationReference.visit(this, data); + JetExpression rangeExpression = condition.getRangeExpression(); + if (rangeExpression != null) { + rangeExpression.visit(this, data); + } + return null; + } + + @Override + public Void visitTypePattern(JetTypePattern pattern, D data) { + return super.visitTypePattern(pattern, data); + } + + @Override + public Void visitWildcardPattern(JetWildcardPattern pattern, D data) { + return super.visitWildcardPattern(pattern, data); + } + + @Override + public Void visitExpressionPattern(JetExpressionPattern pattern, D data) { + JetExpression expression = pattern.getExpression(); + if (expression != null) { + expression.visit(this, data); + } + return null; + } + + @Override + public Void visitTuplePattern(JetTuplePattern pattern, D data) { + List entries = pattern.getEntries(); + for (JetTuplePatternEntry entry : entries) { + entry.visit(this, data); + } + return null; + } + + @Override + public Void visitDecomposerPattern(JetDecomposerPattern pattern, D data) { + JetTuplePattern argumentList = pattern.getArgumentList(); + argumentList.visit(this, data); + JetExpression decomposerExpression = pattern.getDecomposerExpression(); + if (decomposerExpression != null) { + decomposerExpression.visit(this, data); + } + return null; + } + + @Override + public Void visitObjectDeclaration(JetObjectDeclaration objectDeclaration, D data) { + List declarations = objectDeclaration.getDeclarations(); + for (JetDeclaration declaration : declarations) { + declaration.visit(this, data); + } + JetDelegationSpecifierList delegationSpecifierList = objectDeclaration.getDelegationSpecifierList(); + if (delegationSpecifierList != null) { + delegationSpecifierList.visit(this, data); + } + return null; + } + + @Override + public Void visitBindingPattern(JetBindingPattern pattern, D data) { + JetWhenCondition condition = pattern.getCondition(); + if (condition != null) { + condition.visit(this, data); + } + JetProperty variableDeclaration = pattern.getVariableDeclaration(); + variableDeclaration.visit(this, data); + return null; + } + + @Override + public Void visitStringTemplateEntry(JetStringTemplateEntry entry, D data) { + JetExpression expression = entry.getExpression(); + if (expression != null) { + expression.visit(this, data); + } + return null; + } + + @Override + public Void visitStringTemplateEntryWithExpression(JetStringTemplateEntryWithExpression entry, D data) { + visitStringTemplateEntry(entry, data); + return null; + } + + @Override + public Void visitBlockStringTemplateEntry(JetBlockStringTemplateEntry entry, D data) { + visitStringTemplateEntry(entry, data); + return null; + } + + @Override + public Void visitSimpleNameStringTemplateEntry(JetSimpleNameStringTemplateEntry entry, D data) { + visitStringTemplateEntry(entry, data); + return null; + } + + @Override + public Void visitLiteralStringTemplateEntry(JetLiteralStringTemplateEntry entry, D data) { + visitStringTemplateEntry(entry, data); + return null; + } + + @Override + public Void visitEscapeStringTemplateEntry(JetEscapeStringTemplateEntry entry, D data) { + visitStringTemplateEntry(entry, data); + return null; + } + + private Void visitDeclarationWithBody(JetDeclarationWithBody declaration, D data) { + JetExpression bodyExpression = declaration.getBodyExpression(); + if (bodyExpression != null) { + bodyExpression.visit(this, data); + } + List valueParameters = declaration.getValueParameters(); + for (JetParameter valueParameter : valueParameters) { + valueParameter.visit(this, data); + } + return null; + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTreeVisitorVoid.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTreeVisitorVoid.java deleted file mode 100644 index 6b2e4de36e5..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTreeVisitorVoid.java +++ /dev/null @@ -1,728 +0,0 @@ -package org.jetbrains.jet.lang.psi; - -import java.util.List; - -/** - * @author svtk - */ -public class JetTreeVisitorVoid extends JetVisitorVoid { - @Override - public void visitNamespace(JetNamespace namespace) { - List importDirectives = namespace.getImportDirectives(); - for (JetImportDirective directive : importDirectives) { - directive.accept(this); - } - List declarations = namespace.getDeclarations(); - for (JetDeclaration declaration : declarations) { - declaration.accept(this); - } - } - - @Override - public void visitClass(JetClass klass) { - List declarations = klass.getDeclarations(); - for (JetDeclaration declaration : declarations) { - declaration.accept(this); - } - } - - @Override - public void visitClassObject(JetClassObject classObject) { - JetObjectDeclaration objectDeclaration = classObject.getObjectDeclaration(); - if (objectDeclaration != null) { - objectDeclaration.accept(this); - } - } - - @Override - public void visitConstructor(JetConstructor constructor) { - visitDeclarationWithBody(constructor); - } - - @Override - public void visitNamedFunction(JetNamedFunction function) { - visitDeclarationWithBody(function); - } - - @Override - public void visitProperty(JetProperty property) { - List accessors = property.getAccessors(); - for (JetPropertyAccessor accessor : accessors) { - accessor.accept(this); - } - JetExpression initializer = property.getInitializer(); - if (initializer != null) { - initializer.accept(this); - } - } - - @Override - public void visitTypedef(JetTypedef typedef) { - super.visitTypedef(typedef); - } - - @Override - public void visitJetFile(JetFile file) { - JetNamespace rootNamespace = file.getRootNamespace(); - rootNamespace.accept(this); - } - - @Override - public void visitImportDirective(JetImportDirective importDirective) { - super.visitImportDirective(importDirective); - } - - @Override - public void visitClassBody(JetClassBody classBody) { - List declarations = classBody.getDeclarations(); - for (JetDeclaration declaration : declarations) { - declaration.accept(this); - } - List secondaryConstructors = classBody.getSecondaryConstructors(); - for (JetConstructor constructor : secondaryConstructors) { - constructor.accept(this); - } - } - - @Override - public void visitNamespaceBody(JetNamespaceBody body) { - List declarations = body.getDeclarations(); - for (JetDeclaration declaration : declarations) { - declaration.accept(this); - } - } - - @Override - public void visitModifierList(JetModifierList list) { - super.visitModifierList(list); - } - - @Override - public void visitAnnotation(JetAnnotation annotation) { - super.visitAnnotation(annotation); - } - - @Override - public void visitAnnotationEntry(JetAnnotationEntry annotationEntry) { - super.visitAnnotationEntry(annotationEntry); - } - - @Override - public void visitTypeParameterList(JetTypeParameterList list) { - List parameters = list.getParameters(); - for (JetTypeParameter parameter : parameters) { - parameter.accept(this); - } - } - - @Override - public void visitTypeParameter(JetTypeParameter parameter) { - super.visitTypeParameter(parameter); - } - - @Override - public void visitEnumEntry(JetEnumEntry enumEntry) { - List delegationSpecifiers = enumEntry.getDelegationSpecifiers(); - for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) { - delegationSpecifier.accept(this); - } - JetModifierList modifierList = enumEntry.getModifierList(); - if (modifierList != null) { - modifierList.accept(this); - } - } - - @Override - public void visitParameterList(JetParameterList list) { - List parameters = list.getParameters(); - for (JetParameter parameter : parameters) { - parameter.accept(this); - } - } - - @Override - public void visitParameter(JetParameter parameter) { - super.visitParameter(parameter); - } - - @Override - public void visitDelegationSpecifierList(JetDelegationSpecifierList list) { - List delegationSpecifiers = list.getDelegationSpecifiers(); - for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) { - delegationSpecifier.accept(this); - } - } - - @Override - public void visitDelegationSpecifier(JetDelegationSpecifier specifier) { - super.visitDelegationSpecifier(specifier); - } - - @Override - public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) { - super.visitDelegationByExpressionSpecifier(specifier); - } - - @Override - public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) { - super.visitDelegationToSuperCallSpecifier(call); - } - - @Override - public void visitDelegationToSuperClassSpecifier(JetDelegatorToSuperClass specifier) { - super.visitDelegationToSuperClassSpecifier(specifier); - } - - @Override - public void visitDelegationToThisCall(JetDelegatorToThisCall thisCall) { - super.visitDelegationToThisCall(thisCall); - } - - @Override - public void visitTypeReference(JetTypeReference typeReference) { - super.visitTypeReference(typeReference); - } - - @Override - public void visitValueArgumentList(JetValueArgumentList list) { - List arguments = list.getArguments(); - for (JetValueArgument argument : arguments) { - argument.accept(this); - } - } - - @Override - public void visitArgument(JetValueArgument argument) { - super.visitArgument(argument); - } - - @Override - public void visitLoopExpression(JetLoopExpression loopExpression) { - JetExpression body = loopExpression.getBody(); - if (body != null) { - body.accept(this); - } - } - - @Override - public void visitConstantExpression(JetConstantExpression expression) { - super.visitConstantExpression(expression); - } - - @Override - public void visitSimpleNameExpression(JetSimpleNameExpression expression) { - super.visitSimpleNameExpression(expression); - } - - @Override - public void visitReferenceExpression(JetReferenceExpression expression) { - super.visitReferenceExpression(expression); - } - - @Override - public void visitTupleExpression(JetTupleExpression expression) { - super.visitTupleExpression(expression); - } - - @Override - public void visitPrefixExpression(JetPrefixExpression expression) { - JetExpression baseExpression = expression.getBaseExpression(); - if (baseExpression != null) { - baseExpression.accept(this); - } - } - - @Override - public void visitPostfixExpression(JetPostfixExpression expression) { - JetExpression baseExpression = expression.getBaseExpression(); - baseExpression.accept(this); - } - - @Override - public void visitUnaryExpression(JetUnaryExpression expression) { - JetExpression baseExpression = expression.getBaseExpression(); - assert baseExpression != null; - baseExpression.accept(this); - } - - @Override - public void visitBinaryExpression(JetBinaryExpression expression) { - JetExpression left = expression.getLeft(); - left.accept(this); - JetExpression right = expression.getRight(); - if (right != null) { - right.accept(this); - } - super.visitBinaryExpression(expression); - } - - @Override - public void visitReturnExpression(JetReturnExpression expression) { - JetExpression returnedExpression = expression.getReturnedExpression(); - if (returnedExpression != null) { - returnedExpression.accept(this); - } - } - - @Override - public void visitLabelQualifiedExpression(JetLabelQualifiedExpression expression) { - JetExpression labeledExpression = expression.getLabeledExpression(); - if (labeledExpression != null) { - labeledExpression.accept(this); - } - } - - @Override - public void visitThrowExpression(JetThrowExpression expression) { - JetExpression thrownExpression = expression.getThrownExpression(); - if (thrownExpression != null) { - thrownExpression.accept(this); - } - } - - @Override - public void visitBreakExpression(JetBreakExpression expression) { - super.visitBreakExpression(expression); - } - - @Override - public void visitContinueExpression(JetContinueExpression expression) { - super.visitContinueExpression(expression); - } - - @Override - public void visitIfExpression(JetIfExpression expression) { - JetExpression condition = expression.getCondition(); - if (condition != null) { - condition.accept(this); - } - JetExpression then = expression.getThen(); - if (then != null) { - then.accept(this); - } - JetExpression anElse = expression.getElse(); - if (anElse != null) { - anElse.accept(this); - } - } - - @Override - public void visitWhenExpression(JetWhenExpression expression) { - List entries = expression.getEntries(); - for (JetWhenEntry entry : entries) { - entry.accept(this); - } - JetExpression subjectExpression = expression.getSubjectExpression(); - if (subjectExpression != null) { - subjectExpression.accept(this); - } - } - - @Override - public void visitTryExpression(JetTryExpression expression) { - JetBlockExpression tryBlock = expression.getTryBlock(); - tryBlock.accept(this); - List catchClauses = expression.getCatchClauses(); - for (JetCatchClause catchClause : catchClauses) { - catchClause.accept(this); - } - JetFinallySection finallyBlock = expression.getFinallyBlock(); - if (finallyBlock != null) { - finallyBlock.accept(this); - } - } - - @Override - public void visitForExpression(JetForExpression expression) { - JetParameter loopParameter = expression.getLoopParameter(); - if (loopParameter != null) { - loopParameter.accept(this); - } - JetExpression loopRange = expression.getLoopRange(); - if (loopRange != null) { - loopRange.accept(this); - } - visitLoopExpression(expression); - } - - @Override - public void visitWhileExpression(JetWhileExpression expression) { - JetExpression condition = expression.getCondition(); - if (condition != null) { - condition.accept(this); - } - visitLoopExpression(expression); - } - - @Override - public void visitDoWhileExpression(JetDoWhileExpression expression) { - JetExpression condition = expression.getCondition(); - if (condition != null) { - condition.accept(this); - } - visitLoopExpression(expression); - } - - @Override - public void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression) { - JetFunctionLiteral functionLiteral = expression.getFunctionLiteral(); - functionLiteral.accept(this); - visitDeclarationWithBody(expression); - } - - @Override - public void visitAnnotatedExpression(JetAnnotatedExpression expression) { - JetExpression baseExpression = expression.getBaseExpression(); - baseExpression.accept(this); - } - - @Override - public void visitCallExpression(JetCallExpression expression) { - JetExpression calleeExpression = expression.getCalleeExpression(); - if (calleeExpression != null) { - calleeExpression.accept(this); - } - } - - @Override - public void visitArrayAccessExpression(JetArrayAccessExpression expression) { - JetExpression arrayExpression = expression.getArrayExpression(); - arrayExpression.accept(this); - List indexExpressions = expression.getIndexExpressions(); - for (JetExpression indexExpression : indexExpressions) { - indexExpression.accept(this); - } - } - - @Override - public void visitQualifiedExpression(JetQualifiedExpression expression) { - JetExpression receiver = expression.getReceiverExpression(); - receiver.accept(this); - JetExpression selector = expression.getSelectorExpression(); - if (selector != null) { - selector.accept(this); - } - } - - @Override - public void visitHashQualifiedExpression(JetHashQualifiedExpression expression) { - visitQualifiedExpression(expression); - } - - @Override - public void visitDotQualifiedExpression(JetDotQualifiedExpression expression) { - visitQualifiedExpression(expression); - } - - @Override - public void visitPredicateExpression(JetPredicateExpression expression) { - visitQualifiedExpression(expression); - } - - @Override - public void visitSafeQualifiedExpression(JetSafeQualifiedExpression expression) { - visitQualifiedExpression(expression); - } - - @Override - public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) { - JetObjectDeclaration objectDeclaration = expression.getObjectDeclaration(); - objectDeclaration.accept(this); - } - - @Override - public void visitRootNamespaceExpression(JetRootNamespaceExpression expression) { - super.visitRootNamespaceExpression(expression); - } - - @Override - public void visitBlockExpression(JetBlockExpression expression) { - List statements = expression.getStatements(); - for (JetElement statement : statements) { - statement.accept(this); - } - } - - @Override - public void visitCatchSection(JetCatchClause catchClause) { - JetParameter catchParameter = catchClause.getCatchParameter(); - if (catchParameter != null) { - catchParameter.accept(this); - } - JetExpression catchBody = catchClause.getCatchBody(); - if (catchBody != null) { - catchBody.accept(this); - } - } - - @Override - public void visitFinallySection(JetFinallySection finallySection) { - JetBlockExpression finalExpression = finallySection.getFinalExpression(); - finalExpression.accept(this); - } - - @Override - public void visitTypeArgumentList(JetTypeArgumentList typeArgumentList) { - List arguments = typeArgumentList.getArguments(); - for (JetTypeProjection argument : arguments) { - argument.accept(this); - } - } - - @Override - public void visitThisExpression(JetThisExpression expression) { - JetReferenceExpression thisReference = expression.getThisReference(); - thisReference.accept(this); - JetTypeReference superTypeQualifier = expression.getSuperTypeQualifier(); - if (superTypeQualifier != null) { - superTypeQualifier.accept(this); - } - visitLabelQualifiedExpression(expression); - } - - @Override - public void visitParenthesizedExpression(JetParenthesizedExpression expression) { - JetExpression innerExpression = expression.getExpression(); - if (innerExpression != null) { - innerExpression.accept(this); - } - } - - @Override - public void visitInitializerList(JetInitializerList list) { - List initializers = list.getInitializers(); - for (JetDelegationSpecifier initializer : initializers) { - initializer.accept(this); - } - } - - @Override - public void visitAnonymousInitializer(JetClassInitializer initializer) { - JetExpression body = initializer.getBody(); - body.accept(this); - } - - @Override - public void visitPropertyAccessor(JetPropertyAccessor accessor) { - visitDeclarationWithBody(accessor); - } - - @Override - public void visitTypeConstraintList(JetTypeConstraintList list) { - List constraints = list.getConstraints(); - for (JetTypeConstraint constraint : constraints) { - constraint.accept(this); - } - } - - @Override - public void visitTypeConstraint(JetTypeConstraint constraint) { - JetSimpleNameExpression subjectTypeParameterName = constraint.getSubjectTypeParameterName(); - if (subjectTypeParameterName != null) { - subjectTypeParameterName.accept(this); - } - } - - @Override - public void visitUserType(JetUserType type) { - super.visitUserType(type); - } - - @Override - public void visitTupleType(JetTupleType type) { - super.visitTupleType(type); - } - - @Override - public void visitFunctionType(JetFunctionType type) { - super.visitFunctionType(type); - } - - @Override - public void visitSelfType(JetSelfType type) { - super.visitSelfType(type); - } - - @Override - public void visitBinaryWithTypeRHSExpression(JetBinaryExpressionWithTypeRHS expression) { - JetExpression left = expression.getLeft(); - left.accept(this); - JetTypeReference right = expression.getRight(); - if (right != null) { - right.accept(this); - } - } - - @Override - public void visitStringTemplateExpression(JetStringTemplateExpression expression) { - JetStringTemplateEntry[] entries = expression.getEntries(); - for (JetStringTemplateEntry entry : entries) { - entry.accept(this); - } - } - - @Override - public void visitNamedDeclaration(JetNamedDeclaration declaration) { - super.visitNamedDeclaration(declaration); - } - - @Override - public void visitNullableType(JetNullableType nullableType) { - super.visitNullableType(nullableType); - } - - @Override - public void visitTypeProjection(JetTypeProjection typeProjection) { - super.visitTypeProjection(typeProjection); - } - - @Override - public void visitWhenEntry(JetWhenEntry jetWhenEntry) { - JetExpression expression = jetWhenEntry.getExpression(); - if (expression != null) { - expression.accept(this); - } - JetWhenCondition[] conditions = jetWhenEntry.getConditions(); - for (JetWhenCondition condition : conditions) { - condition.accept(this); - } - } - - @Override - public void visitIsExpression(JetIsExpression expression) { - JetExpression leftHandSide = expression.getLeftHandSide(); - leftHandSide.accept(this); - JetSimpleNameExpression operationReference = expression.getOperationReference(); - operationReference.accept(this); - JetPattern pattern = expression.getPattern(); - if (pattern != null) { - pattern.accept(this); - } - } - - @Override - public void visitWhenConditionCall(JetWhenConditionCall condition) { - JetExpression callSuffixExpression = condition.getCallSuffixExpression(); - if (callSuffixExpression != null) { - callSuffixExpression.accept(this); - } - } - - @Override - public void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition) { - JetPattern pattern = condition.getPattern(); - if (pattern != null) { - pattern.accept(this); - } - } - - @Override - public void visitWhenConditionInRange(JetWhenConditionInRange condition) { - JetSimpleNameExpression operationReference = condition.getOperationReference(); - operationReference.accept(this); - JetExpression rangeExpression = condition.getRangeExpression(); - if (rangeExpression != null) { - rangeExpression.accept(this); - } - } - - @Override - public void visitTypePattern(JetTypePattern pattern) { - super.visitTypePattern(pattern); - } - - @Override - public void visitWildcardPattern(JetWildcardPattern pattern) { - super.visitWildcardPattern(pattern); - } - - @Override - public void visitExpressionPattern(JetExpressionPattern pattern) { - JetExpression expression = pattern.getExpression(); - expression.accept(this); - } - - @Override - public void visitTuplePattern(JetTuplePattern pattern) { - List entries = pattern.getEntries(); - for (JetTuplePatternEntry entry : entries) { - entry.accept(this); - } - } - - @Override - public void visitDecomposerPattern(JetDecomposerPattern pattern) { - JetTuplePattern argumentList = pattern.getArgumentList(); - argumentList.accept(this); - JetExpression decomposerExpression = pattern.getDecomposerExpression(); - if (decomposerExpression != null) { - decomposerExpression.accept(this); - } - } - - @Override - public void visitObjectDeclaration(JetObjectDeclaration objectDeclaration) { - List declarations = objectDeclaration.getDeclarations(); - for (JetDeclaration declaration : declarations) { - declaration.accept(this); - } - JetDelegationSpecifierList delegationSpecifierList = objectDeclaration.getDelegationSpecifierList(); - if (delegationSpecifierList != null) { - delegationSpecifierList.accept(this); - } - } - - @Override - public void visitBindingPattern(JetBindingPattern pattern) { - JetWhenCondition condition = pattern.getCondition(); - if (condition != null) { - condition.accept(this); - } - JetProperty variableDeclaration = pattern.getVariableDeclaration(); - variableDeclaration.accept(this); - } - - @Override - public void visitStringTemplateEntry(JetStringTemplateEntry entry) { - JetExpression expression = entry.getExpression(); - if (expression != null) { - expression.accept(this); - } - } - - @Override - public void visitStringTemplateEntryWithExpression(JetStringTemplateEntryWithExpression entry) { - visitStringTemplateEntry(entry); - } - - @Override - public void visitBlockStringTemplateEntry(JetBlockStringTemplateEntry entry) { - visitStringTemplateEntry(entry); - } - - @Override - public void visitSimpleNameStringTemplateEntry(JetSimpleNameStringTemplateEntry entry) { - visitStringTemplateEntry(entry); - } - - @Override - public void visitLiteralStringTemplateEntry(JetLiteralStringTemplateEntry entry) { - visitStringTemplateEntry(entry); - } - - @Override - public void visitEscapeStringTemplateEntry(JetEscapeStringTemplateEntry entry) { - visitStringTemplateEntry(entry); - } - - private void visitDeclarationWithBody(JetDeclarationWithBody declaration) { - JetExpression bodyExpression = declaration.getBodyExpression(); - if (bodyExpression != null) { - bodyExpression.accept(this); - } - List valueParameters = declaration.getValueParameters(); - for (JetParameter valueParameter : valueParameters) { - valueParameter.accept(this); - } - } -} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java index 9e85eadfd73..d4f0dec17dd 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java @@ -58,8 +58,7 @@ public class ControlFlowAnalyzer { private void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor, final @NotNull JetType expectedReturnType) { JetExpression bodyExpression = function.getBodyExpression(); if (bodyExpression == null) return; - - JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData((JetElement)function, bodyExpression); + JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData((JetElement) function, bodyExpression); final boolean blockBody = function.hasBlockBody(); List unreachableElements = Lists.newArrayList(); @@ -105,29 +104,11 @@ public class ControlFlowAnalyzer { } }); } - markDominatedExpressionsAsUnreachable(bodyExpression, scope, expectedReturnType, flowInformationProvider); } - private void markDominatedExpressionsAsUnreachable(JetExpression expression, JetScope scope, JetType expectedReturnType, JetFlowInformationProvider flowInformationProvider) { - JetType type = typeInferrer.getType(scope, expression, expectedReturnType); - if (type == null || !JetStandardClasses.isNothing(type) || type.isNullable()) { - return; - } - - List dominated = new ArrayList(); - flowInformationProvider.collectDominatedExpressions(expression, dominated); - Set rootExpressions = JetPsiUtil.findRootExpressions(dominated); - for (JetElement rootExpression : rootExpressions) { - context.getTrace().report(UNREACHABLE_BECAUSE_OF_NOTHING.on(rootExpression, expression.getText())); - } - } - - private void checkProperty(JetProperty property) { JetExpression initializer = property.getInitializer(); if (initializer == null) return; - JetScope scope = this.context.getDeclaringScopes().get(property); - JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(property, initializer); - markDominatedExpressionsAsUnreachable(initializer, scope, NO_EXPECTED_TYPE, flowInformationProvider); + context.getClassDescriptorResolver().computeFlowData(property, initializer); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index cec4b09de34..7abaef85e08 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -393,7 +393,7 @@ public class JetTypeInferrer { private Map collectReturnedExpressionsWithTypes( @NotNull BindingTrace trace, JetScope outerScope, - JetDeclarationWithBody function, + final JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) { JetExpression bodyExpression = function.getBodyExpression(); assert bodyExpression != null; @@ -402,12 +402,26 @@ public class JetTypeInferrer { //todo function literals final Collection returnedExpressions = new ArrayList(); if (function.hasBlockBody()) { - bodyExpression.accept(new JetTreeVisitorVoid() { + //now this code is never invoked!, it should be invoked for inference of return type of function literal with local returns + bodyExpression.visit(new JetTreeVisitor() { @Override - public void visitReturnExpression(JetReturnExpression expression) { - returnedExpressions.add(expression); + public Void visitReturnExpression(JetReturnExpression expression, JetDeclarationWithBody outerFunction) { + if (expression.getLabeledExpression() == function || outerFunction == function) { + returnedExpressions.add(expression); + } + return null; } - }); + + @Override + public Void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, JetDeclarationWithBody outerFunction) { + return super.visitFunctionLiteralExpression(expression, expression.getFunctionLiteral()); + } + + @Override + public Void visitNamedFunction(JetNamedFunction function, JetDeclarationWithBody outerFunction) { + return super.visitNamedFunction(function, function); + } + }, function); } else { returnedExpressions.add(bodyExpression); @@ -1894,14 +1908,15 @@ public class JetTypeInferrer { private boolean containsBreak(JetLoopExpression expression) { final boolean[] result = new boolean[1]; result[0] = false; - expression.accept(new JetTreeVisitorVoid() { + expression.visit(new JetTreeVisitor() { @Override - public void visitBreakExpression(JetBreakExpression expression) { - //todo get exact loop for this break, compare to expression + public Void visitBreakExpression(JetBreakExpression expression, Void v) { + //todo get exact loop for this break, compare to an expression //expression.getLabeledExpression() result[0] = true; + return null; } - }); + }, null); return result[0]; } diff --git a/idea/testData/cfg/ArrayAccess.instructions b/idea/testData/cfg/ArrayAccess.instructions index ea110204bd7..b2d18a45e79 100644 --- a/idea/testData/cfg/ArrayAccess.instructions +++ b/idea/testData/cfg/ArrayAccess.instructions @@ -36,15 +36,3 @@ l1: error: ===================== -== a == -val a = Array ---------------------- -l0: - - r(Array) - r(Array) -l1: - -error: - -===================== diff --git a/idea/testData/cfg/Assignments.instructions b/idea/testData/cfg/Assignments.instructions index 89fda838fce..07ceb36d2c8 100644 --- a/idea/testData/cfg/Assignments.instructions +++ b/idea/testData/cfg/Assignments.instructions @@ -55,56 +55,3 @@ l1: error: ===================== -== x == -var x = 1 ---------------------- -l0: - - r(1) -l1: - -error: - -===================== -== y == -val y = true && false ---------------------- -l0: - - r(true) - jf(l2) - r(false) -l2: - r(true && false) -l1: - -error: - -===================== -== z == -val z = false && true ---------------------- -l0: - - r(false) - jf(l2) - r(true) -l2: - r(false && true) -l1: - -error: - -===================== -== t == -val t = Test() ---------------------- -l0: - - r(Test) - r(Test()) -l1: - -error: - -===================== diff --git a/idea/testData/checker/UnreachableCode.jet b/idea/testData/checker/UnreachableCode.jet index b34b281adcc..15ba14178fc 100644 --- a/idea/testData/checker/UnreachableCode.jet +++ b/idea/testData/checker/UnreachableCode.jet @@ -136,9 +136,9 @@ fun tf() : Int { } fun failtest(a : Int) : Int { - if (fail() || true) { + if (fail() || true) { - } + } return 1 } diff --git a/idea/testData/checkerWithErrorTypes/full/UnreachableCode.jet b/idea/testData/checkerWithErrorTypes/full/UnreachableCode.jet index 2a72a04117d..432b5e53605 100644 --- a/idea/testData/checkerWithErrorTypes/full/UnreachableCode.jet +++ b/idea/testData/checkerWithErrorTypes/full/UnreachableCode.jet @@ -136,16 +136,16 @@ fun tf() : Int { } fun failtest(a : Int) : Int { - if (fail() || true) { + if (fail() || true) { - } - return 1 + } + return 1 } fun foo(a : Nothing) : Unit { 1 a - 2 + 2 } fun fail() : Nothing { From 8db6aa4ab4da572a523df63550b22b79a0086a07 Mon Sep 17 00:00:00 2001 From: svtk Date: Wed, 12 Oct 2011 15:53:41 +0400 Subject: [PATCH 12/14] Labels resolve removed from control flow graph --- .../jet/lang/cfg/JetControlFlowProcessor.java | 143 ++++++++++-------- .../jet/lang/types/JetTypeInferrer.java | 15 +- 2 files changed, 86 insertions(+), 72 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index aa185dcee86..c841ff2d212 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -1,10 +1,12 @@ package org.jetbrains.jet.lang.cfg; +import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; 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.BindingTrace; import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; @@ -20,7 +22,7 @@ import static org.jetbrains.jet.lang.diagnostics.Errors.*; */ public class JetControlFlowProcessor { - private final Map> labeledElements = new HashMap>(); +// private final Map> labeledElements = new HashMap>(); private final JetControlFlowBuilder builder; private final BindingTrace trace; @@ -35,10 +37,10 @@ public class JetControlFlowProcessor { } public void generateSubroutineControlFlow(@NotNull JetElement subroutineElement, @NotNull List body) { - if (subroutineElement instanceof JetNamedDeclaration) { - JetNamedDeclaration namedDeclaration = (JetNamedDeclaration) subroutineElement; - enterLabeledElement(JetPsiUtil.safeName(namedDeclaration.getName()), namedDeclaration); - } +// if (subroutineElement instanceof JetNamedDeclaration) { +// JetNamedDeclaration namedDeclaration = (JetNamedDeclaration) subroutineElement; +// enterLabeledElement(JetPsiUtil.safeName(namedDeclaration.getName()), namedDeclaration); +// } boolean functionLiteral = subroutineElement instanceof JetFunctionLiteralExpression; builder.enterSubroutine(subroutineElement, functionLiteral); for (JetElement statement : body) { @@ -47,50 +49,50 @@ public class JetControlFlowProcessor { builder.exitSubroutine(subroutineElement, functionLiteral); } - private void enterLabeledElement(@NotNull String labelName, @NotNull JetElement labeledElement) { - Stack stack = labeledElements.get(labelName); - if (stack == null) { - stack = new Stack(); - labeledElements.put(labelName, stack); - } - stack.push(labeledElement); - } +// private void enterLabeledElement(@NotNull String labelName, @NotNull JetElement labeledElement) { +// Stack stack = labeledElements.get(labelName); +// if (stack == null) { +// stack = new Stack(); +// labeledElements.put(labelName, stack); +// } +// stack.push(labeledElement); +// } +// +// private void exitElement(JetElement element) { +// // TODO : really suboptimal +// for (Iterator>> mapIter = labeledElements.entrySet().iterator(); mapIter.hasNext(); ) { +// Map.Entry> entry = mapIter.next(); +// Stack stack = entry.getValue(); +// for (Iterator stackIter = stack.iterator(); stackIter.hasNext(); ) { +// JetElement recorded = stackIter.next(); +// if (recorded == element) { +// stackIter.remove(); +// } +// } +// if (stack.isEmpty()) { +// mapIter.remove(); +// } +// } +// } - private void exitElement(JetElement element) { - // TODO : really suboptimal - for (Iterator>> mapIter = labeledElements.entrySet().iterator(); mapIter.hasNext(); ) { - Map.Entry> entry = mapIter.next(); - Stack stack = entry.getValue(); - for (Iterator stackIter = stack.iterator(); stackIter.hasNext(); ) { - JetElement recorded = stackIter.next(); - if (recorded == element) { - stackIter.remove(); - } - } - if (stack.isEmpty()) { - mapIter.remove(); - } - } - } - - @Nullable - private JetElement resolveLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved) { - Stack stack = labeledElements.get(labelName); - if (stack == null || stack.isEmpty()) { - if (reportUnresolved) { -// trace.report(UNRESOLVED_REFERENCE.on(labelExpression)); - } - return null; - } - else if (stack.size() > 1) { -// trace.getErrorHandler().genericWarning(labelExpression.getNode(), "There is more than one label with such a name in this scope"); -// trace.report(LABEL_NAME_CLASH.on(labelExpression)); - } - - JetElement result = stack.peek(); -// trace.record(BindingContext.LABEL_TARGET, labelExpression, result); - return result; - } +// @Nullable +// private JetElement resolveLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved) { +// Stack stack = labeledElements.get(labelName); +// if (stack == null || stack.isEmpty()) { +// if (reportUnresolved) { +//// trace.report(UNRESOLVED_REFERENCE.on(labelExpression)); +// } +// return null; +// } +// else if (stack.size() > 1) { +//// trace.getErrorHandler().genericWarning(labelExpression.getNode(), "There is more than one label with such a name in this scope"); +//// trace.report(LABEL_NAME_CLASH.on(labelExpression)); +// } +// +// JetElement result = stack.peek(); +//// trace.record(BindingContext.LABEL_TARGET, labelExpression, result); +// return result; +// } private class CFPVisitor extends JetVisitorVoid { private final boolean inCondition; @@ -109,7 +111,7 @@ public class JetControlFlowProcessor { visitor = new CFPVisitor(inCondition); } element.accept(visitor); - exitElement(element); +// exitElement(element); } @Override @@ -122,12 +124,12 @@ public class JetControlFlowProcessor { @Override public void visitThisExpression(JetThisExpression expression) { - JetSimpleNameExpression targetLabel = expression.getTargetLabel(); - if (targetLabel != null) { - String labelName = expression.getLabelName(); - assert labelName != null; - resolveLabel(labelName, targetLabel, false); - } +// JetSimpleNameExpression targetLabel = expression.getTargetLabel(); +// if (targetLabel != null) { +// String labelName = expression.getLabelName(); +// assert labelName != null; +// resolveLabel(labelName, targetLabel, false); +// } builder.read(expression); } @@ -159,7 +161,7 @@ public class JetControlFlowProcessor { private void visitLabeledExpression(@NotNull String labelName, @NotNull JetExpression labeledExpression) { JetExpression deparenthesized = JetPsiUtil.deparenthesize(labeledExpression); if (deparenthesized != null) { - enterLabeledElement(labelName, deparenthesized); +// enterLabeledElement(labelName, deparenthesized); value(labeledExpression, inCondition); } } @@ -443,12 +445,20 @@ public class JetControlFlowProcessor { if (labelName != null) { JetSimpleNameExpression targetLabel = expression.getTargetLabel(); assert targetLabel != null; - loop = resolveLabel(labelName, targetLabel, true); - if (!isLoop(loop)) { -// trace.getErrorHandler().genericError(expression.getNode(), "The label '" + targetLabel.getText() + "' does not denote a loop"); + PsiElement labeledElement = BindingContextUtils.resolveToDeclarationPsiElement(trace.getBindingContext(), targetLabel); + if (labeledElement instanceof JetLoopExpression) { + loop = (JetLoopExpression) labeledElement; + } + else { trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.getText())); loop = null; } +// loop = resolveLabel(labelName, targetLabel, true); +// if (!isLoop(loop)) { +//// trace.getErrorHandler().genericError(expression.getNode(), "The label '" + targetLabel.getText() + "' does not denote a loop"); +// trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.getText())); +// loop = null; +// } } else { loop = builder.getCurrentLoop(); @@ -460,11 +470,11 @@ public class JetControlFlowProcessor { return loop; } - private boolean isLoop(JetElement loop) { - return loop instanceof JetWhileExpression || - loop instanceof JetDoWhileExpression || - loop instanceof JetForExpression; - } +// private boolean isLoop(JetElement loop) { +// return loop instanceof JetWhileExpression || +// loop instanceof JetDoWhileExpression || +// loop instanceof JetForExpression; +// } @Override public void visitReturnExpression(JetReturnExpression expression) { @@ -477,7 +487,10 @@ public class JetControlFlowProcessor { if (labelElement != null) { String labelName = expression.getLabelName(); assert labelName != null; - subroutine = resolveLabel(labelName, labelElement, true); + PsiElement labeledElement = BindingContextUtils.resolveToDeclarationPsiElement(trace.getBindingContext(), labelElement); + assert labeledElement instanceof JetElement; + subroutine = (JetElement) labeledElement; + //subroutine = resolveLabel(labelName, labelElement, true); } else { subroutine = builder.getCurrentSubroutine(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 7abaef85e08..2f2c58b1672 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -1343,11 +1343,11 @@ public class JetTypeInferrer { } else if (size == 0) { //todo (first we put to the context, then get from it) - labelsResolver.resolveLabel(labelName, targetLabel, false, context); + JetElement element = labelsResolver.resolveLabel(labelName, targetLabel, false, context); // This uses the info written by the control flow processor - PsiElement psiElement = BindingContextUtils.resolveToDeclarationPsiElement(context.trace.getBindingContext(), targetLabel); - if (psiElement instanceof JetFunctionLiteralExpression) { - DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiElement); + //PsiElement psiElement = BindingContextUtils.resolveToDeclarationPsiElement(context.trace.getBindingContext(), targetLabel); + if (element instanceof JetFunctionLiteralExpression) { + DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, element); if (declarationDescriptor instanceof FunctionDescriptor) { thisReceiver = ((FunctionDescriptor) declarationDescriptor).getReceiver(); if (thisReceiver.exists()) { @@ -2911,7 +2911,7 @@ public class JetTypeInferrer { } } - private void resolveLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved, TypeInferenceContext context) { + private JetElement resolveLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved, TypeInferenceContext context) { Collection declarationsByLabel = context.scope.getDeclarationsByLabel(labelName); int size = declarationsByLabel.size(); @@ -2930,7 +2930,7 @@ public class JetTypeInferrer { throw new UnsupportedOperationException(); // TODO } context.trace.record(LABEL_TARGET, labelExpression, element); - return; + return element; } Stack stack = labeledElements.get(labelName); @@ -2938,7 +2938,7 @@ public class JetTypeInferrer { if (reportUnresolved) { context.trace.report(UNRESOLVED_REFERENCE.on(labelExpression)); } - return; + return null; } else if (stack.size() > 1) { context.trace.report(LABEL_NAME_CLASH.on(labelExpression)); @@ -2946,6 +2946,7 @@ public class JetTypeInferrer { JetElement result = stack.peek(); context.trace.record(BindingContext.LABEL_TARGET, labelExpression, result); + return result; } private void resolveCorrespondingLoopLabel(JetLabelQualifiedExpression expression, TypeInferenceContext context) { From d9b4c972f7ae7835665380d5af2816ead39a65ae Mon Sep 17 00:00:00 2001 From: svtk Date: Thu, 13 Oct 2011 15:48:56 +0400 Subject: [PATCH 13/14] Added return label check --- .../jet/lang/cfg/JetControlFlowProcessor.java | 16 +- .../jet/lang/diagnostics/Errors.java | 1 + .../jet/lang/types/JetTypeInferrer.java | 146 +++++++++--------- .../checkerWithErrorTypes/full/Return.jet | 17 ++ 4 files changed, 104 insertions(+), 76 deletions(-) create mode 100644 idea/testData/checkerWithErrorTypes/full/Return.jet diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index c841ff2d212..07337a81a63 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -488,15 +488,20 @@ public class JetControlFlowProcessor { String labelName = expression.getLabelName(); assert labelName != null; PsiElement labeledElement = BindingContextUtils.resolveToDeclarationPsiElement(trace.getBindingContext(), labelElement); - assert labeledElement instanceof JetElement; - subroutine = (JetElement) labeledElement; + if (labeledElement != null) { + assert labeledElement instanceof JetElement; + subroutine = (JetElement) labeledElement; + } + else { + subroutine = null; + } //subroutine = resolveLabel(labelName, labelElement, true); } else { subroutine = builder.getCurrentSubroutine(); // TODO : a context check } - if (subroutine != null) { + if (subroutine instanceof JetFunction || subroutine instanceof JetFunctionLiteralExpression) { if (returnedExpression == null) { builder.returnNoValue(expression, subroutine); } @@ -504,6 +509,11 @@ public class JetControlFlowProcessor { builder.returnValue(expression, subroutine); } } + else { + if (labelElement != null) { + trace.report(NOT_A_RETURN_LABEL.on(expression, expression.getLabelName())); + } + } } @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index f92959e2ef7..5c1990f36e7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -222,6 +222,7 @@ public interface Errors { SimpleDiagnosticFactory VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION = SimpleDiagnosticFactory.create(ERROR, "A type annotation is required on a value parameter"); SimpleDiagnosticFactory BREAK_OR_CONTINUE_OUTSIDE_A_LOOP = SimpleDiagnosticFactory.create(ERROR, "'break' and 'continue' are only allowed inside a loop"); ParameterizedDiagnosticFactory1 NOT_A_LOOP_LABEL = ParameterizedDiagnosticFactory1.create(ERROR, "The label ''{0}'' does not denote a loop"); + ParameterizedDiagnosticFactory1 NOT_A_RETURN_LABEL = ParameterizedDiagnosticFactory1.create(ERROR, "The label ''{0}'' does not reference to a context from which we can return"); SimpleDiagnosticFactory ANONYMOUS_INITIALIZER_WITHOUT_CONSTRUCTOR = SimpleDiagnosticFactory.create(ERROR, "Anonymous initializers are only allowed in the presence of a primary constructor"); SimpleDiagnosticFactory NULLABLE_SUPERTYPE = SimpleDiagnosticFactory.create(ERROR, "A supertype cannot be nullable"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 2f2c58b1672..25e7ce8c69f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -295,7 +295,7 @@ public class JetTypeInferrer { private void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, FunctionDescriptor functionDescriptor, @NotNull final JetType expectedReturnType, @NotNull DataFlowInfo dataFlowInfo) { JetExpression bodyExpression = function.getBodyExpression(); - assert bodyExpression != null; + if (bodyExpression == null) return; final boolean blockBody = function.hasBlockBody(); final TypeInferenceContext context = @@ -1167,12 +1167,7 @@ public class JetTypeInferrer { @Override public JetType visitReturnExpression(JetReturnExpression expression, TypeInferenceContext context) { - JetSimpleNameExpression labelElement = expression.getTargetLabel(); - if (labelElement != null) { - String labelName = expression.getLabelName(); - assert labelName != null; - labelsResolver.resolveLabel(labelName, labelElement, true, context); - } + labelsResolver.recordLabel(expression, context); if (context.expectedReturnType == FORBIDDEN) { // context.trace.getErrorHandler().genericError(expression.getNode(), "'return' is not allowed here"); context.trace.report(RETURN_NOT_ALLOWED.on(expression)); @@ -1195,13 +1190,13 @@ public class JetTypeInferrer { @Override public JetType visitBreakExpression(JetBreakExpression expression, TypeInferenceContext context) { - labelsResolver.resolveCorrespondingLoopLabel(expression, context); + labelsResolver.recordLabel(expression, context); return context.services.checkType(JetStandardClasses.getNothingType(), expression, context); } @Override public JetType visitContinueExpression(JetContinueExpression expression, TypeInferenceContext context) { - labelsResolver.resolveCorrespondingLoopLabel(expression, context); + labelsResolver.recordLabel(expression, context); return context.services.checkType(JetStandardClasses.getNothingType(), expression, context); } @@ -1321,52 +1316,7 @@ public class JetTypeInferrer { ReceiverDescriptor thisReceiver = null; String labelName = expression.getLabelName(); if (labelName != null) { - Collection declarationsByLabel = context.scope.getDeclarationsByLabel(labelName); - int size = declarationsByLabel.size(); - final JetSimpleNameExpression targetLabel = expression.getTargetLabel(); - assert targetLabel != null; - if (size == 1) { - DeclarationDescriptor declarationDescriptor = declarationsByLabel.iterator().next(); - if (declarationDescriptor instanceof ClassDescriptor) { - ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; - thisReceiver = classDescriptor.getImplicitReceiver(); - } - else if (declarationDescriptor instanceof FunctionDescriptor) { - FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor; - thisReceiver = functionDescriptor.getReceiver(); - } - else { - throw new UnsupportedOperationException(); // TODO - } - context.trace.record(REFERENCE_TARGET, targetLabel, declarationDescriptor); - context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor); - } - else if (size == 0) { - //todo (first we put to the context, then get from it) - JetElement element = labelsResolver.resolveLabel(labelName, targetLabel, false, context); - // This uses the info written by the control flow processor - //PsiElement psiElement = BindingContextUtils.resolveToDeclarationPsiElement(context.trace.getBindingContext(), targetLabel); - if (element instanceof JetFunctionLiteralExpression) { - DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, element); - if (declarationDescriptor instanceof FunctionDescriptor) { - thisReceiver = ((FunctionDescriptor) declarationDescriptor).getReceiver(); - if (thisReceiver.exists()) { - context.trace.record(REFERENCE_TARGET, targetLabel, declarationDescriptor); - context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor); - } - } - else { - context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel)); - } - } - else { - context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel)); - } - } - else { -// context.trace.getErrorHandler().genericError(targetLabel.getNode(), "Ambiguous label"); - context.trace.report(AMBIGUOUS_LABEL.on(targetLabel)); - } + thisReceiver = labelsResolver.resolveThisLabel(expression, context, thisReceiver, labelName); } else { thisReceiver = context.scope.getImplicitReceiver(); @@ -2881,7 +2831,7 @@ public class JetTypeInferrer { private class LabelsResolver { private final Map> labeledElements = new HashMap>(); - private void enterLabeledElement(@NotNull String labelName, @NotNull JetExpression labeledExpression) { + public void enterLabeledElement(@NotNull String labelName, @NotNull JetExpression labeledExpression) { JetExpression deparenthesized = JetPsiUtil.deparenthesize(labeledExpression); if (deparenthesized != null) { Stack stack = labeledElements.get(labelName); @@ -2893,7 +2843,7 @@ public class JetTypeInferrer { } } - private void exitLabeledElement(JetExpression expression) { + public void exitLabeledElement(@NotNull JetExpression expression) { JetExpression deparenthesized = JetPsiUtil.deparenthesize(expression); // TODO : really suboptimal for (Iterator>> mapIter = labeledElements.entrySet().iterator(); mapIter.hasNext(); ) { @@ -2911,20 +2861,15 @@ public class JetTypeInferrer { } } - private JetElement resolveLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved, TypeInferenceContext context) { + private JetElement resolveControlLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved, TypeInferenceContext context) { Collection declarationsByLabel = context.scope.getDeclarationsByLabel(labelName); int size = declarationsByLabel.size(); - + if (size == 1) { DeclarationDescriptor declarationDescriptor = declarationsByLabel.iterator().next(); JetElement element; - if (declarationDescriptor instanceof ClassDescriptor) { - ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; - element = (JetElement) context.trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, classDescriptor); - } - else if (declarationDescriptor instanceof FunctionDescriptor) { - FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor; - element = (JetElement) context.trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, functionDescriptor); + if (declarationDescriptor instanceof FunctionDescriptor || declarationDescriptor instanceof ClassDescriptor) { + element = (JetElement) context.trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, declarationDescriptor); } else { throw new UnsupportedOperationException(); // TODO @@ -2932,7 +2877,23 @@ public class JetTypeInferrer { context.trace.record(LABEL_TARGET, labelExpression, element); return element; } - + else if (size == 0) { + return resolveNamedLabel(labelName, labelExpression, reportUnresolved, context); + } + context.trace.report(AMBIGUOUS_LABEL.on(labelExpression)); + return null; + } + + public void recordLabel(JetLabelQualifiedExpression expression, TypeInferenceContext context) { + JetSimpleNameExpression labelElement = expression.getTargetLabel(); + if (labelElement != null) { + String labelName = expression.getLabelName(); + assert labelName != null; + resolveControlLabel(labelName, labelElement, true, context); + } + } + + private JetElement resolveNamedLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved, TypeInferenceContext context) { Stack stack = labeledElements.get(labelName); if (stack == null || stack.isEmpty()) { if (reportUnresolved) { @@ -2949,13 +2910,52 @@ public class JetTypeInferrer { return result; } - private void resolveCorrespondingLoopLabel(JetLabelQualifiedExpression expression, TypeInferenceContext context) { - String labelName = expression.getLabelName(); - if (labelName != null) { - JetSimpleNameExpression targetLabel = expression.getTargetLabel(); - assert targetLabel != null; - resolveLabel(labelName, targetLabel, true, context); + public ReceiverDescriptor resolveThisLabel(JetThisExpression expression, TypeInferenceContext context, ReceiverDescriptor thisReceiver, String labelName) { + Collection declarationsByLabel = context.scope.getDeclarationsByLabel(labelName); + int size = declarationsByLabel.size(); + final JetSimpleNameExpression targetLabel = expression.getTargetLabel(); + assert targetLabel != null; + if (size == 1) { + DeclarationDescriptor declarationDescriptor = declarationsByLabel.iterator().next(); + if (declarationDescriptor instanceof ClassDescriptor) { + ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; + thisReceiver = classDescriptor.getImplicitReceiver(); + } + else if (declarationDescriptor instanceof FunctionDescriptor) { + FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor; + thisReceiver = functionDescriptor.getReceiver(); + } + else { + throw new UnsupportedOperationException(); // TODO + } + PsiElement element = context.trace.get(DESCRIPTOR_TO_DECLARATION, declarationDescriptor); + assert element != null; + context.trace.record(LABEL_TARGET, targetLabel, element); + context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor); } + else if (size == 0) { + JetElement element = labelsResolver.resolveNamedLabel(labelName, targetLabel, false, context); + if (element instanceof JetFunctionLiteralExpression) { + DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, element); + if (declarationDescriptor instanceof FunctionDescriptor) { + thisReceiver = ((FunctionDescriptor) declarationDescriptor).getReceiver(); + if (thisReceiver.exists()) { + context.trace.record(LABEL_TARGET, targetLabel, element); + context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor); + } + } + else { + context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel)); + } + } + else { + context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel)); + } + } + else { + context.trace.report(AMBIGUOUS_LABEL.on(targetLabel)); + } + return thisReceiver; } } } diff --git a/idea/testData/checkerWithErrorTypes/full/Return.jet b/idea/testData/checkerWithErrorTypes/full/Return.jet new file mode 100644 index 00000000000..5b087076efe --- /dev/null +++ b/idea/testData/checkerWithErrorTypes/full/Return.jet @@ -0,0 +1,17 @@ +namespace return + +class A { + fun outer() { + fun inner() { + if (1 < 2) + return@inner + else + return@outer + } + if (1 < 2) + return@A + else if (2 < 3) + return@inner + return@outer + } +} From e32409e4bfa0f4f59fa3318adf68dad4067ba2fc Mon Sep 17 00:00:00 2001 From: svtk Date: Thu, 13 Oct 2011 17:15:10 +0400 Subject: [PATCH 14/14] 'containsBreak' checks that 'break' belongs to the right loop --- .../jet/lang/types/JetTypeInferrer.java | 32 +++++++---- .../full/BreakContinue.jet | 57 +++++++++++++++++++ 2 files changed, 78 insertions(+), 11 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 25e7ce8c69f..2e83d2523e4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -391,7 +391,7 @@ public class JetTypeInferrer { } private Map collectReturnedExpressionsWithTypes( - @NotNull BindingTrace trace, + final @NotNull BindingTrace trace, JetScope outerScope, final JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) { @@ -406,7 +406,9 @@ public class JetTypeInferrer { bodyExpression.visit(new JetTreeVisitor() { @Override public Void visitReturnExpression(JetReturnExpression expression, JetDeclarationWithBody outerFunction) { - if (expression.getLabeledExpression() == function || outerFunction == function) { + JetSimpleNameExpression targetLabel = expression.getTargetLabel(); + PsiElement element = targetLabel != null ? trace.get(LABEL_TARGET, targetLabel) : null; + if (element == function || (targetLabel == null && outerFunction == function)) { returnedExpressions.add(expression); } return null; @@ -1848,25 +1850,33 @@ public class JetTypeInferrer { DataFlowInfo conditionInfo = condition == null ? context.dataFlowInfo : extractDataFlowInfoFromCondition(condition, true, scopeToExtend, context); getTypeWithNewScopeAndDataFlowInfo(scopeToExtend, body, conditionInfo, context); } - if (!containsBreak(expression)) { + if (!containsBreak(expression, context)) { // resultScope = newWritableScopeImpl(); resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false, null, context); } return context.services.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType); } - private boolean containsBreak(JetLoopExpression expression) { + private boolean containsBreak(final JetLoopExpression loopExpression, final TypeInferenceContext context) { final boolean[] result = new boolean[1]; result[0] = false; - expression.visit(new JetTreeVisitor() { + //todo breaks in inline function literals + loopExpression.visit(new JetTreeVisitor() { @Override - public Void visitBreakExpression(JetBreakExpression expression, Void v) { - //todo get exact loop for this break, compare to an expression - //expression.getLabeledExpression() - result[0] = true; + public Void visitBreakExpression(JetBreakExpression breakExpression, JetLoopExpression outerLoop) { + JetSimpleNameExpression targetLabel = breakExpression.getTargetLabel(); + PsiElement element = targetLabel != null ? context.trace.get(LABEL_TARGET, targetLabel) : null; + if (element == loopExpression || (targetLabel == null && outerLoop == loopExpression)) { + result[0] = true; + } return null; } - }, null); + + @Override + public Void visitLoopExpression(JetLoopExpression loopExpression, JetLoopExpression outerLoop) { + return super.visitLoopExpression(loopExpression, loopExpression); + } + }, loopExpression); return result[0]; } @@ -1894,7 +1904,7 @@ public class JetTypeInferrer { } JetExpression condition = expression.getCondition(); checkCondition(conditionScope, condition, context); - if (!containsBreak(expression)) { + if (!containsBreak(expression, context)) { // resultScope = newWritableScopeImpl(); resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false, null, context); } diff --git a/idea/testData/checkerWithErrorTypes/full/BreakContinue.jet b/idea/testData/checkerWithErrorTypes/full/BreakContinue.jet index 2bf691799e0..b26847730e4 100644 --- a/idea/testData/checkerWithErrorTypes/full/BreakContinue.jet +++ b/idea/testData/checkerWithErrorTypes/full/BreakContinue.jet @@ -25,4 +25,61 @@ class C { break@f } + fun containsBreak(a: String?, b: String?) { + while (a == null) { + break; + } + a?.compareTo("2") + } + + fun notContainsBreak(a: String?, b: String?) { + while (a == null) { + while (b == null) { + break; + } + } + a?.compareTo("2") + } + + fun containsBreakWithLabel(a: String?) { + @loop while(a == null) { + break@loop + } + a?.compareTo("2") + } + + fun containsIllegalBreak(a: String?) { + @loop while(a == null) { + break@label + } + a?.compareTo("2") + } + + fun containsBreakToOuterLoop(a: String?, b: String?) { + @loop while(b == null) { + while(a == null) { + break@loop + } + a?.compareTo("2") + } + } + + fun containsBreakInsideLoopWithLabel(a: String?, array: Array) { + @ while(a == null) { + for (el in array) { + break@ + } + } + a?.compareTo("2") + } + + fun unresolvedBreak(a: String?, array: Array) { + while(a == null) { + @ for (el in array) { + break + } + if (true) break else break@ + } + a?.compareTo("2") + } } \ No newline at end of file