diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassContext.java index 81d06bf4ea8..e0fe6e08cb3 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClassContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassContext.java @@ -73,7 +73,7 @@ public class ClassContext { thisIdx++; } - final boolean hasReceiver = descriptor.getReceiver().exists(); + final boolean hasReceiver = descriptor.getReceiverParameter().exists(); if (hasReceiver) { thisIdx++; } @@ -104,7 +104,7 @@ public class ClassContext { } private ReceiverDescriptor receiver() { - return contextType instanceof FunctionDescriptor ? ((FunctionDescriptor) contextType).getReceiver() : ReceiverDescriptor.NO_RECEIVER; + return contextType instanceof FunctionDescriptor ? ((FunctionDescriptor) contextType).getReceiverParameter() : ReceiverDescriptor.NO_RECEIVER; } private boolean hasReceiver() { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 864111bee96..2e04ada073d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -42,7 +42,7 @@ public class ClosureCodegen { } public static Method erasedInvokeSignature(FunctionDescriptor fd) { - boolean isExtensionFunction = fd.getReceiver().exists(); + boolean isExtensionFunction = fd.getReceiverParameter().exists(); int paramCount = fd.getValueParameters().size(); if (isExtensionFunction) { paramCount++; @@ -117,7 +117,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); @@ -151,7 +151,7 @@ public class ClosureCodegen { iv.load(0, Type.getObjectType(className)); - final ReceiverDescriptor receiver = funDescriptor.getReceiver(); + final ReceiverDescriptor receiver = funDescriptor.getReceiverParameter(); int count = 1; if (receiver.exists()) { StackValue.local(count, JetTypeMapper.TYPE_OBJECT).put(JetTypeMapper.TYPE_OBJECT, iv); @@ -175,7 +175,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 +199,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) { @@ -229,7 +231,7 @@ public class ClosureCodegen { public static String getInternalClassName(FunctionDescriptor descriptor) { final int paramCount = descriptor.getValueParameters().size(); - if (descriptor.getReceiver().exists()) { + if (descriptor.getReceiverParameter().exists()) { return "jet/ExtensionFunction" + paramCount; } else { @@ -250,7 +252,7 @@ public class ClosureCodegen { Method descriptor = erasedInvokeSignature(fd); String owner = getInternalClassName(fd); final CallableMethod result = new CallableMethod(owner, descriptor, Opcodes.INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes())); - if (fd.getReceiver().exists()) { + if (fd.getReceiverParameter().exists()) { result.setNeedsReceiver(null); } result.requestGenerateCallee(Type.getObjectType(getInternalClassName(fd))); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 91c126fd77d..f231cdf3426 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -52,8 +52,10 @@ public class ExpressionCodegen extends JetVisitor { private final InstructionAdapter v; private final FrameMap myMap; private final JetTypeMapper typeMapper; + private final GenerationState state; private final Type returnType; + private final BindingContext bindingContext; private final Map typeParameterExpressions = new HashMap(); private final ClassContext context; @@ -74,6 +76,14 @@ public class ExpressionCodegen extends JetVisitor { this.intrinsics = state.getIntrinsics(); } + public GenerationState getState() { + return state; + } + + public BindingContext getBindingContext() { + return bindingContext; + } + public JetTypeMapper getTypeMapper() { return state.getTypeMapper(); } @@ -207,7 +217,7 @@ public class ExpressionCodegen extends JetVisitor { else { assert expressionType != null; final DeclarationDescriptor descriptor = expressionType.getConstructor().getDeclarationDescriptor(); - if (isClass(descriptor, "IntRange")) { // TODO IntRange subclasses + if (isClass(descriptor, "IntRange")) { // TODO IntRange subclasses (now IntRange is final) new ForInRangeLoopGenerator(expression, loopRangeType).invoke(); return StackValue.none(); } @@ -921,7 +931,7 @@ public class ExpressionCodegen extends JetVisitor { callableMethod = ClosureCodegen.asCallableMethod((FunctionDescriptor) fd); } else if (fd instanceof FunctionDescriptor) { - callableMethod = ClosureCodegen.asCallableMethod((FunctionDescriptor) fd); + callableMethod = typeMapper.mapToCallableMethod((FunctionDescriptor) fd, null); } else { throw new UnsupportedOperationException("can't resolve declaration to callable: " + fd); @@ -2076,7 +2086,7 @@ public class ExpressionCodegen extends JetVisitor { } } - void generateTypeInfo(JetType jetType) { + public void generateTypeInfo(JetType jetType) { String knownTypeInfo = typeMapper.isKnownTypeInfo(jetType); if(knownTypeInfo != null) { v.getstatic("jet/typeinfo/TypeInfo", knownTypeInfo, "Ljet/typeinfo/TypeInfo;"); @@ -2287,7 +2297,7 @@ public class ExpressionCodegen extends JetVisitor { JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, rangeExpression); assert jetType != null; final DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); - if (isClass(descriptor, "IntRange")) { // TODO IntRange subclasses + if (isClass(descriptor, "IntRange")) { return true; } } @@ -2308,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;"); } @@ -2316,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/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 61a1584b381..b8e221c52a9 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -2,7 +2,6 @@ package org.jetbrains.jet.codegen; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; -import jet.Function1; import jet.JetObject; import jet.typeinfo.TypeInfo; import jet.typeinfo.TypeInfoProjection; @@ -58,6 +57,8 @@ public class JetTypeMapper { private final HashMap knowTypes = new HashMap(); public static final Type TYPE_FUNCTION1 = Type.getObjectType("jet/Function1"); + public static final Type TYPE_ITERATOR = Type.getObjectType("jet/Iterator"); + public static final Type TYPE_INT_RANGE = Type.getObjectType("jet/IntRange"); public JetTypeMapper(JetStandardLibrary standardLibrary, BindingContext bindingContext) { this.standardLibrary = standardLibrary; @@ -317,6 +318,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); } @@ -461,17 +465,16 @@ public class JetTypeMapper { } - private Method mapSignature(JetNamedFunction f, List valueParameterTypes, OwnerKind kind) { - final JetTypeReference receiverTypeRef = f.getReceiverTypeRef(); - final JetType receiverType = receiverTypeRef == null ? null : bindingContext.get(BindingContext.TYPE, receiverTypeRef); - final List parameters = f.getValueParameters(); + private Method mapSignature(FunctionDescriptor f, List valueParameterTypes, OwnerKind kind) { + final ReceiverDescriptor receiverTypeRef = f.getReceiverParameter(); + final JetType receiverType = !receiverTypeRef.exists() ? 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")) { @@ -481,24 +484,15 @@ public class JetTypeMapper { valueParameterTypes.add(type); parameterTypes.add(type); } - for (JetParameter parameter : parameters) { - final Type type = mapType(bindingContext.get(BindingContext.TYPE, parameter.getTypeReference())); + for (ValueParameterDescriptor parameter : parameters) { + final Type type = mapType(parameter.getOutType()); valueParameterTypes.add(type); parameterTypes.add(type); } for (int n = f.getTypeParameters().size(); n > 0; n--) { parameterTypes.add(TYPE_TYPEINFO); } - final JetTypeReference returnTypeRef = f.getReturnTypeRef(); - Type returnType; - if (returnTypeRef == null) { - assert functionDescriptor != null; - final JetType type = functionDescriptor.getReturnType(); - returnType = mapReturnType(type); - } - else { - returnType = mapReturnType(bindingContext.get(BindingContext.TYPE, returnTypeRef)); - } + Type returnType = mapReturnType(f.getReturnType()); return new Method(f.getName(), returnType, parameterTypes.toArray(new Type[parameterTypes.size()])); } @@ -512,9 +506,13 @@ public class JetTypeMapper { JetNamedFunction f = (JetNamedFunction) declaration; final FunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, f); assert functionDescriptor != null; + return mapToCallableMethod(functionDescriptor, kind); + } + + public CallableMethod mapToCallableMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) { final DeclarationDescriptor functionParent = functionDescriptor.getContainingDeclaration(); final List valueParameterTypes = new ArrayList(); - Method descriptor = mapSignature(f, valueParameterTypes, kind); + Method descriptor = mapSignature(functionDescriptor.getOriginal(), valueParameterTypes, kind); String owner; int invokeOpcode; boolean needsReceiver; @@ -522,7 +520,7 @@ public class JetTypeMapper { if (functionParent instanceof NamespaceDescriptor) { owner = NamespaceCodegen.getJVMClassName(DescriptorRenderer.getFQName(functionParent)); invokeOpcode = Opcodes.INVOKESTATIC; - needsReceiver = f.getReceiverTypeRef() != null; + needsReceiver = functionDescriptor.getReceiverParameter().exists(); } else if (functionParent instanceof ClassDescriptor) { ClassDescriptor containingClass = (ClassDescriptor) functionParent; @@ -546,7 +544,7 @@ public class JetTypeMapper { } public Method mapSignature(String name, FunctionDescriptor f) { - final ReceiverDescriptor receiver = f.getReceiver(); + final ReceiverDescriptor receiver = f.getReceiverParameter(); final List parameters = f.getValueParameters(); List parameterTypes = new ArrayList(); if (receiver.exists()) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ProjectionErasingJetType.java b/compiler/backend/src/org/jetbrains/jet/codegen/ProjectionErasingJetType.java new file mode 100644 index 00000000000..d48101b811c --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ProjectionErasingJetType.java @@ -0,0 +1,67 @@ +package org.jetbrains.jet.codegen; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeConstructor; +import org.jetbrains.jet.lang.types.TypeProjection; +import org.jetbrains.jet.lang.types.Variance; + +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/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java index 7a7c280f8e1..f60fc9804cc 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java @@ -197,6 +197,9 @@ public abstract class StackValue { if (type.getSort() == Type.BOOLEAN) { v.checkcast(JetTypeMapper.JL_BOOLEAN_TYPE); } + else if (type.getSort() == Type.CHAR) { + v.checkcast(JetTypeMapper.JL_CHAR_TYPE); + } else { v.checkcast(JetTypeMapper.JL_NUMBER_TYPE); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIndices.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIndices.java new file mode 100644 index 00000000000..4049e238e43 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIndices.java @@ -0,0 +1,21 @@ +package org.jetbrains.jet.codegen.intrinsics; + +import com.intellij.psi.PsiElement; +import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.JetTypeMapper; +import org.jetbrains.jet.codegen.StackValue; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.InstructionAdapter; + +import java.util.List; + +public class ArrayIndices implements IntrinsicMethod { + @Override + public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { + receiver.put(JetTypeMapper.TYPE_OBJECT, v); + v.arraylength(); + v.invokestatic("jet/IntRange", "count", "(I)Ljet/IntRange;"); + return StackValue.onStack(JetTypeMapper.TYPE_INT_RANGE); + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIterator.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIterator.java new file mode 100644 index 00000000000..c61130a7b15 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIterator.java @@ -0,0 +1,65 @@ +package org.jetbrains.jet.codegen.intrinsics; + +import com.intellij.psi.PsiElement; +import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.JetTypeMapper; +import org.jetbrains.jet.codegen.StackValue; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.psi.JetCallExpression; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.types.JetStandardLibrary; +import org.jetbrains.jet.lang.types.JetType; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.InstructionAdapter; + +import java.util.List; + +/** + * @author alex.tkachman + */ +public class ArrayIterator implements IntrinsicMethod { + @Override + public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { + receiver.put(JetTypeMapper.TYPE_OBJECT, v); + JetCallExpression call = (JetCallExpression) element; + FunctionDescriptor funDescriptor = (FunctionDescriptor) codegen.getBindingContext().get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) call.getCalleeExpression()); + ClassDescriptor containingDeclaration = (ClassDescriptor) funDescriptor.getContainingDeclaration().getOriginal(); + JetStandardLibrary standardLibrary = codegen.getState().getStandardLibrary(); + if(containingDeclaration.equals(standardLibrary.getArray())) { + codegen.generateTypeInfo(funDescriptor.getReturnType().getArguments().get(0).getType()); + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([Ljava/lang/Object;Ljet/typeinfo/TypeInfo;)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getByteArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([B)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getShortArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([S)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getIntArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([I)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getLongArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([J)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getFloatArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([F)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getDoubleArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([D)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getCharArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([C)Ljet/Iterator;"); + } + else if(containingDeclaration.equals(standardLibrary.getBooleanArrayClass())) { + v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([Z)Ljet/Iterator;"); + } + else { + throw new UnsupportedOperationException(containingDeclaration.toString()); + } + return StackValue.onStack(JetTypeMapper.TYPE_ITERATOR); + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java index ce4c0e29b46..b1efba96116 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java @@ -29,11 +29,13 @@ public class IntrinsicMethods { private static final IntrinsicMethod DEC = new Increment(-1); private static final List PRIMITIVE_NUMBER_TYPES = ImmutableList.of("Boolean", "Byte", "Char", "Short", "Int", "Float", "Long", "Double"); - public static final ArraySize ARRAY_SIZE = new ArraySize(); + public static final IntrinsicMethod ARRAY_SIZE = new ArraySize(); + public static final IntrinsicMethod ARRAY_INDICES = new ArrayIndices(); private final Project myProject; private final JetStandardLibrary myStdLib; private final Map myMethods = new HashMap(); + private static final IntrinsicMethod ARRAY_ITERATOR = new ArrayIterator(); public IntrinsicMethods(Project project, JetStandardLibrary stdlib) { myProject = project; @@ -87,6 +89,30 @@ public class IntrinsicMethods { declareIntrinsicProperty("DoubleArray", "size", ARRAY_SIZE); declareIntrinsicProperty("CharArray", "size", ARRAY_SIZE); declareIntrinsicProperty("BooleanArray", "size", ARRAY_SIZE); + + declareIntrinsicProperty("Array", "indices", ARRAY_INDICES); + declareIntrinsicProperty("ByteArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("ShortArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("IntArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("LongArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("FloatArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("DoubleArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("CharArray", "indices", ARRAY_INDICES); + declareIntrinsicProperty("BooleanArray", "indices", ARRAY_INDICES); + + declareIterator(myStdLib.getArray()); + declareIterator(myStdLib.getByteArrayClass()); + declareIterator(myStdLib.getShortArrayClass()); + declareIterator(myStdLib.getIntArrayClass()); + declareIterator(myStdLib.getLongArrayClass()); + declareIterator(myStdLib.getFloatArrayClass()); + declareIterator(myStdLib.getDoubleArrayClass()); + declareIterator(myStdLib.getCharArrayClass()); + declareIterator(myStdLib.getBooleanArrayClass()); + } + + private void declareIterator(ClassDescriptor classDescriptor) { + declareOverload(classDescriptor.getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR); } private void declareIntrinsicStringMethods() { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/RangeTo.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/RangeTo.java index 79953a13b0f..86850d21051 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/RangeTo.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/RangeTo.java @@ -16,21 +16,15 @@ import java.util.List; * @author yole */ public class RangeTo implements IntrinsicMethod { - private static final String INT_RANGE_CONSTRUCTOR_DESCRIPTOR = "(II)V"; - private static final Type INT_RANGE_TYPE = Type.getType(IntRange.class); - private static final String CLASS_INT_RANGE = "jet/IntRange"; - @Override public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { JetBinaryExpression expression = (JetBinaryExpression) element; final Type leftType = codegen.expressionType(expression.getLeft()); if (JetTypeMapper.isIntPrimitive(leftType)) { - v.anew(INT_RANGE_TYPE); - v.dup(); codegen.gen(expression.getLeft(), Type.INT_TYPE); codegen.gen(expression.getRight(), Type.INT_TYPE); - v.invokespecial(CLASS_INT_RANGE, "", INT_RANGE_CONSTRUCTOR_DESCRIPTOR); - return StackValue.onStack(INT_RANGE_TYPE); + v.invokestatic("jet/IntRange", "rangeTo", "(II)Ljet/IntRange;"); + return StackValue.onStack(JetTypeMapper.TYPE_INT_RANGE); } else { throw new UnsupportedOperationException("ranges are only supported for int objects"); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaClassDescriptor.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaClassDescriptor.java index f1fed5d2201..4327be71475 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaClassDescriptor.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaClassDescriptor.java @@ -3,14 +3,12 @@ package org.jetbrains.jet.lang.resolve.java; import com.google.common.collect.Sets; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.SubstitutingScope; import org.jetbrains.jet.lang.resolve.scopes.receivers.ClassReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.*; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; @@ -22,7 +20,7 @@ public class JavaClassDescriptor extends MutableDeclarationDescriptor implements private TypeConstructor typeConstructor; private JavaClassMembersScope unsubstitutedMemberScope; - private JetType classObjectType; +// private JetType classObjectType; private final Set constructors = Sets.newLinkedHashSet(); private Modality modality; private Visibility visibility; @@ -52,19 +50,19 @@ public class JavaClassDescriptor extends MutableDeclarationDescriptor implements this.unsubstitutedMemberScope = memberScope; } - public void setClassObjectMemberScope(JavaClassMembersScope memberScope) { - classObjectType = new JetTypeImpl( - new TypeConstructorImpl( - JavaDescriptorResolver.JAVA_CLASS_OBJECT, - Collections.emptyList(), - true, - "Class object emulation for " + getName(), - Collections.emptyList(), - Collections.emptyList() - ), - memberScope - ); - } +// public void setClassObjectMemberScope(JavaClassMembersScope memberScope) { +// classObjectType = new JetTypeImpl( +// new TypeConstructorImpl( +// JavaDescriptorResolver.JAVA_CLASS_OBJECT, +// Collections.emptyList(), +// true, +// "Class object emulation for " + getName(), +// Collections.emptyList(), +// Collections.emptyList() +// ), +// memberScope +// ); +// } public void addConstructor(ConstructorDescriptor constructorDescriptor) { this.constructors.add(constructorDescriptor); @@ -133,7 +131,7 @@ public class JavaClassDescriptor extends MutableDeclarationDescriptor implements @Override public JetType getClassObjectType() { - return classObjectType; + return null; } @Override diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java index c5485602ba5..ab02a9d9d42 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java @@ -27,8 +27,8 @@ public class JavaClassMembersScope implements JetScope { private final Map classifiers = Maps.newHashMap(); private Collection allDescriptors; - public JavaClassMembersScope(@NotNull DeclarationDescriptor classDescriptor, PsiClass psiClass, JavaSemanticServices semanticServices, boolean staticMembers) { - this.containingDeclaration = classDescriptor; + public JavaClassMembersScope(@NotNull DeclarationDescriptor classOrNamespaceDescriptor, PsiClass psiClass, JavaSemanticServices semanticServices, boolean staticMembers) { + this.containingDeclaration = classOrNamespaceDescriptor; this.psiClass = psiClass; this.semanticServices = semanticServices; this.staticMembers = staticMembers; @@ -161,11 +161,11 @@ public class JavaClassMembersScope implements JetScope { @NotNull @Override public ReceiverDescriptor getImplicitReceiver() { - throw new UnsupportedOperationException(); // Should never occur, we don't sit in a Java class... + return ReceiverDescriptor.NO_RECEIVER; // Should never occur, we don't sit in a Java class... } @Override public void getImplicitReceiversHierarchy(@NotNull List result) { - throw new UnsupportedOperationException(); // Should never occur, we don't sit in a Java class... + // we cannot really be scoped inside here } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index 738ee857c9d..fc591498479 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -12,6 +12,7 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingTrace; +import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.types.*; import java.util.*; @@ -53,7 +54,7 @@ public class JavaDescriptorResolver { protected final Map typeParameterDescriptorCache = Maps.newHashMap(); protected final Map methodDescriptorCache = Maps.newHashMap(); protected final Map fieldDescriptorCache = Maps.newHashMap(); - protected final Map namespaceDescriptorCache = Maps.newHashMap(); + protected final Map namespaceDescriptorCache = Maps.newHashMap(); protected final JavaPsiFacade javaFacade; protected final GlobalSearchScope javaSearchScope; protected final JavaSemanticServices semanticServices; @@ -108,7 +109,6 @@ public class JavaDescriptorResolver { name, typeParameters, supertypes - )); classDescriptor.setModality(Modality.convertFromFlags( psiClass.hasModifierProperty(PsiModifier.ABSTRACT) || psiClass.isInterface(), @@ -117,7 +117,7 @@ public class JavaDescriptorResolver { classDescriptor.setVisibility(resolveVisibilityFromPsiModifiers(semanticServices.getTrace(), psiClass)); classDescriptorCache.put(psiClass.getQualifiedName(), classDescriptor); classDescriptor.setUnsubstitutedMemberScope(new JavaClassMembersScope(classDescriptor, psiClass, semanticServices, false)); - classDescriptor.setClassObjectMemberScope(new JavaClassMembersScope(classDescriptor, psiClass, semanticServices, true)); +// classDescriptor.setClassObjectMemberScope(new JavaClassMembersScope(classDescriptor, psiClass, semanticServices, true)); // UGLY HACK supertypes.addAll(getSupertypes(psiClass)); if (psiClass.isInterface()) { @@ -238,7 +238,9 @@ public class JavaDescriptorResolver { public NamespaceDescriptor resolveNamespace(String qualifiedName) { PsiPackage psiPackage = javaFacade.findPackage(qualifiedName); if (psiPackage == null) { - return null; + PsiClass psiClass = javaFacade.findClass(qualifiedName, javaSearchScope); + if (psiClass == null) return null; + return resolveNamespace(psiClass); } return resolveNamespace(psiPackage); } @@ -246,20 +248,21 @@ public class JavaDescriptorResolver { private NamespaceDescriptor resolveNamespace(@NotNull PsiPackage psiPackage) { NamespaceDescriptor namespaceDescriptor = namespaceDescriptorCache.get(psiPackage); if (namespaceDescriptor == null) { - // TODO : packages - -// PsiClass psiClass = javaFacade.findClass(qualifiedName, javaSearchScope); -// if (psiClass != null) { -// namespaceDescriptor = createJavaNamespaceDescriptor(psiClass); -// } -// else { - namespaceDescriptor = createJavaNamespaceDescriptor(psiPackage); -// } + namespaceDescriptor = createJavaNamespaceDescriptor(psiPackage); namespaceDescriptorCache.put(psiPackage, namespaceDescriptor); } return namespaceDescriptor; } + private NamespaceDescriptor resolveNamespace(@NotNull PsiClass psiClass) { + NamespaceDescriptor namespaceDescriptor = namespaceDescriptorCache.get(psiClass); + if (namespaceDescriptor == null) { + namespaceDescriptor = createJavaNamespaceDescriptor(psiClass); + namespaceDescriptorCache.put(psiClass, namespaceDescriptor); + } + return namespaceDescriptor; + } + private NamespaceDescriptor createJavaNamespaceDescriptor(@NotNull PsiPackage psiPackage) { String name = psiPackage.getName(); JavaNamespaceDescriptor namespaceDescriptor = new JavaNamespaceDescriptor( @@ -325,6 +328,7 @@ public class JavaDescriptorResolver { resolveVisibilityFromPsiModifiers(semanticServices.getTrace(), field), !isFinal, null, + DescriptorUtils.getExpectedThisObjectIfNeeded(containingDeclaration), field.getName(), isFinal ? null : type, type); @@ -399,6 +403,7 @@ public class JavaDescriptorResolver { methodDescriptorCache.put(method, functionDescriptorImpl); functionDescriptorImpl.initialize( null, + DescriptorUtils.getExpectedThisObjectIfNeeded(owner), resolveTypeParameters(functionDescriptorImpl, method.getTypeParameters()), semanticServices.getDescriptorResolver().resolveParameterDescriptors(functionDescriptorImpl, parameters), semanticServices.getTypeTransformer().transformToType(returnType), diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java index 2b69b86e161..11b92aee25a 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java @@ -11,7 +11,6 @@ import java.util.Set; * @author abreslav */ public class JavaPackageScope extends JetScopeImpl { - private final JavaSemanticServices semanticServices; private final DeclarationDescriptor containingDescriptor; private final String packagePrefix; diff --git a/compiler/frontend/src/jet/Library.jet b/compiler/frontend/src/jet/Library.jet index f11575b99d3..0a57bbf4c91 100644 --- a/compiler/frontend/src/jet/Library.jet +++ b/compiler/frontend/src/jet/Library.jet @@ -42,7 +42,7 @@ fun Any?.toString() : String// = this === other trait Iterator { fun next() : T - abstract fun hasNext() : Boolean + fun hasNext() : Boolean } trait Iterable { @@ -54,6 +54,8 @@ class Array(val size : Int, init : fun(Int) : T = null ) { fun set(index : Int, value : T) : Unit fun iterator() : Iterator + + val indices : IntRange } class ByteArray(val size : Int) { @@ -61,6 +63,8 @@ class ByteArray(val size : Int) { fun set(index : Int, value : Byte) : Unit fun iterator() : Iterator + + val indices : IntRange } class ShortArray(val size : Int) { @@ -68,6 +72,8 @@ class ShortArray(val size : Int) { fun set(index : Int, value : Short) : Unit fun iterator() : Iterator + + val indices : IntRange } class IntArray(val size : Int) { @@ -75,6 +81,8 @@ class IntArray(val size : Int) { fun set(index : Int, value : Int) : Unit fun iterator() : Iterator + + val indices : IntRange } class LongArray(val size : Int) { @@ -82,6 +90,8 @@ class LongArray(val size : Int) { fun set(index : Int, value : Long) : Unit fun iterator() : Iterator + + val indices : IntRange } class FloatArray(val size : Int) { @@ -89,6 +99,8 @@ class FloatArray(val size : Int) { fun set(index : Int, value : Float) : Unit fun iterator() : Iterator + + val indices : IntRange } class DoubleArray(val size : Int) { @@ -96,6 +108,8 @@ class DoubleArray(val size : Int) { fun set(index : Int, value : Double) : Unit fun iterator() : Iterator + + val indices : IntRange } class CharArray(val size : Int) { @@ -103,6 +117,8 @@ class CharArray(val size : Int) { fun set(index : Int, value : Char) : Unit fun iterator() : Iterator + + val indices : IntRange } class BooleanArray(val size : Int) { @@ -110,6 +126,8 @@ class BooleanArray(val size : Int) { fun set(index : Int, value : Boolean) : Unit fun iterator() : Iterator + + val indices : IntRange } trait Comparable { @@ -152,8 +170,28 @@ trait Range> { fun contains(item : T) : Boolean } -class IntRange>(val start : Int, val end : Int) : Range, Iterable { +class IntRange(val start : Int, size : Int, reversed : Boolean = false) : Range, Iterable { + fun iterator () : Iterator + fun contains (elem: Int) : Boolean + + val size : Int + + val end : Int + + val reversed : Boolean +} + +class LongRange(val start : Long, size : Long, reversed : Boolean = false) : Range, Iterable { + fun iterator () : Iterator + + fun contains (elem: Long) : Boolean + + val size : Long + + val end : Long + + val reversed : Boolean } abstract class Number : Hashable { @@ -349,11 +387,11 @@ class Long : Number, Comparable { fun rangeTo(other : Double) : Range fun rangeTo(other : Float) : Range - fun rangeTo(other : Long) : IntRange - fun rangeTo(other : Int) : IntRange - fun rangeTo(other : Short) : IntRange - fun rangeTo(other : Byte) : IntRange - fun rangeTo(other : Char) : IntRange + fun rangeTo(other : Long) : LongRange + fun rangeTo(other : Int) : LongRange + fun rangeTo(other : Short) : LongRange + fun rangeTo(other : Byte) : LongRange + fun rangeTo(other : Char) : LongRange fun inc() : Long fun dec() : Long @@ -420,11 +458,11 @@ class Int : Number, Comparable { fun rangeTo(other : Double) : Range fun rangeTo(other : Float) : Range - fun rangeTo(other : Long) : IntRange - fun rangeTo(other : Int) : IntRange - fun rangeTo(other : Short) : IntRange - fun rangeTo(other : Byte) : IntRange - fun rangeTo(other : Char) : IntRange + fun rangeTo(other : Long) : LongRange + fun rangeTo(other : Int) : IntRange + fun rangeTo(other : Short) : IntRange + fun rangeTo(other : Byte) : IntRange + fun rangeTo(other : Char) : IntRange fun inc() : Int fun dec() : Int @@ -491,11 +529,11 @@ class Char : Number, Comparable { fun rangeTo(other : Double) : Range fun rangeTo(other : Float) : Range - fun rangeTo(other : Long) : IntRange - fun rangeTo(other : Int) : IntRange - fun rangeTo(other : Short) : IntRange - fun rangeTo(other : Byte) : IntRange - fun rangeTo(other : Char) : IntRange + fun rangeTo(other : Long) : LongRange + fun rangeTo(other : Int) : IntRange + fun rangeTo(other : Short) : IntRange + fun rangeTo(other : Byte) : IntRange + fun rangeTo(other : Char) : IntRange fun inc() : Char fun dec() : Char @@ -554,11 +592,11 @@ class Short : Number, Comparable { fun rangeTo(other : Double) : Range fun rangeTo(other : Float) : Range - fun rangeTo(other : Long) : IntRange - fun rangeTo(other : Int) : IntRange - fun rangeTo(other : Short) : IntRange - fun rangeTo(other : Byte) : IntRange - fun rangeTo(other : Char) : IntRange + fun rangeTo(other : Long) : LongRange + fun rangeTo(other : Int) : IntRange + fun rangeTo(other : Short) : IntRange + fun rangeTo(other : Byte) : IntRange + fun rangeTo(other : Char) : IntRange fun inc() : Short fun dec() : Short @@ -617,11 +655,11 @@ class Byte : Number, Comparable { fun rangeTo(other : Double) : Range fun rangeTo(other : Float) : Range - fun rangeTo(other : Long) : IntRange - fun rangeTo(other : Int) : IntRange - fun rangeTo(other : Short) : IntRange - fun rangeTo(other : Byte) : IntRange - fun rangeTo(other : Char) : IntRange + fun rangeTo(other : Long) : LongRange + fun rangeTo(other : Int) : IntRange + fun rangeTo(other : Short) : IntRange + fun rangeTo(other : Byte) : IntRange + fun rangeTo(other : Char) : IntRange fun inc() : Byte fun dec() : Byte diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/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/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 5c6a6707b46..07337a81a63 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -1,11 +1,15 @@ 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; import org.jetbrains.jet.lang.types.JetTypeInferrer; import org.jetbrains.jet.lexer.JetTokens; @@ -18,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; @@ -33,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) { @@ -45,57 +49,55 @@ 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 preferBlock; private final boolean inCondition; private CFPVisitor(boolean inCondition) { -// this.preferBlock = preferBlock; this.inCondition = 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); } @@ -139,6 +141,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 @@ -153,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); } } @@ -437,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(); @@ -454,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) { @@ -471,13 +487,21 @@ 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); + 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); } @@ -485,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 @@ -524,6 +553,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) { @@ -549,6 +584,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/descriptors/CallableDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/CallableDescriptor.java index 47eac9f2bee..4e78d2c81f5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/CallableDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/CallableDescriptor.java @@ -1,7 +1,6 @@ package org.jetbrains.jet.lang.descriptors; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.resolve.scopes.receivers.ImplicitReceiverDescriptor; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeSubstitutor; @@ -14,7 +13,10 @@ import java.util.Set; */ public interface CallableDescriptor extends DeclarationDescriptor { @NotNull - ReceiverDescriptor getReceiver(); + ReceiverDescriptor getReceiverParameter(); + + @NotNull + ReceiverDescriptor getExpectedThisObject(); @NotNull List getTypeParameters(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ConstructorDescriptorImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ConstructorDescriptorImpl.java index 5afac7ed85c..084e5004cdf 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ConstructorDescriptorImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ConstructorDescriptorImpl.java @@ -3,6 +3,8 @@ package org.jetbrains.jet.lang.descriptors; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.resolve.DescriptorUtils; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.JetType; import java.util.Collections; @@ -28,16 +30,27 @@ public class ConstructorDescriptorImpl extends FunctionDescriptorImpl implements @Override @Deprecated - public FunctionDescriptorImpl initialize(@Nullable JetType receiverType, @NotNull List typeParameters, @NotNull List unsubstitutedValueParameters, @Nullable JetType unsubstitutedReturnType, Modality modality, @NotNull Visibility visibility) { + public FunctionDescriptorImpl initialize(@Nullable JetType receiverType, @NotNull ReceiverDescriptor expectedThisObject, @NotNull List typeParameters, @NotNull List unsubstitutedValueParameters, @Nullable JetType unsubstitutedReturnType, Modality modality, @NotNull Visibility visibility) { assert receiverType == null; - return super.initialize(null, typeParameters, unsubstitutedValueParameters, unsubstitutedReturnType, modality, visibility); + return super.initialize(null, expectedThisObject, typeParameters, unsubstitutedValueParameters, unsubstitutedReturnType, modality, visibility); } public ConstructorDescriptorImpl initialize(@NotNull List typeParameters, @NotNull List unsubstitutedValueParameters, Modality modality, Visibility visibility) { - super.initialize(null, typeParameters, unsubstitutedValueParameters, null, modality, visibility); + super.initialize(null, getExpectedThisObject(getContainingDeclaration()), typeParameters, unsubstitutedValueParameters, null, modality, visibility); return this; } + @NotNull + private static ReceiverDescriptor getExpectedThisObject(@NotNull DeclarationDescriptor descriptor) { + if (descriptor instanceof ConstructorDescriptor) { + ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) descriptor; + ClassDescriptor classDescriptor = constructorDescriptor.getContainingDeclaration(); + return getExpectedThisObject(classDescriptor); + } + DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); + return DescriptorUtils.getExpectedThisObjectIfNeeded(containingDeclaration); + } + @NotNull @Override public ClassDescriptor getContainingDeclaration() { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java index a6c3f0b9872..ef3ab5aefa0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java @@ -8,6 +8,7 @@ import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver; import org.jetbrains.jet.lang.types.DescriptorSubstitutor; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeSubstitutor; @@ -27,6 +28,7 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements private List unsubstitutedValueParameters; private JetType unsubstitutedReturnType; private ReceiverDescriptor receiver; + private ReceiverDescriptor expectedThisObject; private Modality modality; private Visibility visibility; @@ -51,6 +53,7 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements public FunctionDescriptorImpl initialize( @Nullable JetType receiverType, + @NotNull ReceiverDescriptor expectedThisObject, @NotNull List typeParameters, @NotNull List unsubstitutedValueParameters, @Nullable JetType unsubstitutedReturnType, @@ -62,6 +65,7 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements this.modality = modality; this.visibility = visibility; this.receiver = receiverType == null ? NO_RECEIVER : new ExtensionReceiver(this, receiverType); + this.expectedThisObject = expectedThisObject; return this; } @@ -71,10 +75,16 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements @NotNull @Override - public ReceiverDescriptor getReceiver() { + public ReceiverDescriptor getReceiverParameter() { return receiver; } + @NotNull + @Override + public ReceiverDescriptor getExpectedThisObject() { + return expectedThisObject; + } + @NotNull @Override public Set getOverriddenDescriptors() { @@ -132,12 +142,21 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements TypeSubstitutor substitutor = DescriptorSubstitutor.substituteTypeParameters(getTypeParameters(), originalSubstitutor, substitutedDescriptor, substitutedTypeParameters); JetType substitutedReceiverType = null; - if (receiver != NO_RECEIVER) { - substitutedReceiverType = substitutor.substitute(getReceiver().getType(), Variance.IN_VARIANCE); + if (receiver.exists()) { + substitutedReceiverType = substitutor.substitute(getReceiverParameter().getType(), Variance.IN_VARIANCE); if (substitutedReceiverType == null) { return null; } } + + ReceiverDescriptor substitutedExpectedThis = NO_RECEIVER; + if (expectedThisObject.exists()) { + JetType substitutedType = substitutor.substitute(expectedThisObject.getType(), Variance.INVARIANT); + if (substitutedType == null) { + return null; + } + substitutedExpectedThis = new TransientReceiver(substitutedType); + } List substitutedValueParameters = FunctionDescriptorUtil.getSubstitutedValueParameters(substitutedDescriptor, this, substitutor); if (substitutedValueParameters == null) { @@ -151,6 +170,7 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements substitutedDescriptor.initialize( substitutedReceiverType, + substitutedExpectedThis, substitutedTypeParameters, substitutedValueParameters, substitutedReturnType, @@ -181,7 +201,8 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements public FunctionDescriptor copy(DeclarationDescriptor newOwner, boolean makeNonAbstract) { FunctionDescriptorImpl copy = new FunctionDescriptorImpl(newOwner, Lists.newArrayList(getAnnotations()), getName()); copy.initialize( - getReceiver().exists() ? getReceiver().getType() : null, + getReceiverParameter().exists() ? getReceiverParameter().getType() : null, + expectedThisObject, DescriptorUtils.copyTypeParameters(copy, typeParameters), DescriptorUtils.copyValueParameters(copy, unsubstitutedValueParameters), unsubstitutedReturnType, diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java index 07a14eece99..3990e09e9a7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java @@ -95,7 +95,7 @@ public class FunctionDescriptorUtil { @NotNull public static JetScope getFunctionInnerScope(@NotNull JetScope outerScope, @NotNull FunctionDescriptor descriptor, @NotNull BindingTrace trace) { WritableScope parameterScope = new WritableScopeImpl(outerScope, descriptor, new TraceBasedRedeclarationHandler(trace)).setDebugName("Function inner scope"); - ReceiverDescriptor receiver = descriptor.getReceiver(); + ReceiverDescriptor receiver = descriptor.getReceiverParameter(); if (receiver.exists()) { parameterScope.setImplicitReceiver(receiver); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyAccessorDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyAccessorDescriptor.java index 023a235c3d8..cf0a0c8be05 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyAccessorDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyAccessorDescriptor.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.descriptors; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.TypeSubstitutor; import java.util.Collections; @@ -77,6 +78,18 @@ public abstract class PropertyAccessorDescriptor extends DeclarationDescriptorIm return correspondingProperty; } + @NotNull + @Override + public ReceiverDescriptor getReceiverParameter() { + return getCorrespondingProperty().getReceiverParameter(); + } + + @NotNull + @Override + public ReceiverDescriptor getExpectedThisObject() { + return getCorrespondingProperty().getExpectedThisObject(); + } + @NotNull @Override public PropertyAccessorDescriptor copy(DeclarationDescriptor newOwner, boolean makeNonAbstract) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java index 5c6c5212c78..354979ecac9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java @@ -8,6 +8,7 @@ import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeSubstitutor; import org.jetbrains.jet.lang.types.Variance; @@ -24,6 +25,7 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab private final Visibility visibility; private final boolean isVar; private final ReceiverDescriptor receiver; + private final ReceiverDescriptor expectedThisObject; private final Set overriddenProperties = Sets.newLinkedHashSet(); private final List typeParemeters = Lists.newArrayListWithCapacity(0); private final PropertyDescriptor original; @@ -38,6 +40,7 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab @NotNull Visibility visibility, boolean isVar, @Nullable JetType receiverType, + @NotNull ReceiverDescriptor expectedThisObject, @NotNull String name, @Nullable JetType inType, @NotNull JetType outType) { @@ -48,6 +51,7 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab this.modality = modality; this.visibility = visibility; this.receiver = receiverType == null ? ReceiverDescriptor.NO_RECEIVER : new ExtensionReceiver(this, receiverType); + this.expectedThisObject = expectedThisObject; this.original = original == null ? this : original.getOriginal(); } @@ -58,15 +62,17 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab @NotNull Visibility visibility, boolean isVar, @Nullable JetType receiverType, + @NotNull ReceiverDescriptor expectedThisObject, @NotNull String name, @Nullable JetType inType, @NotNull JetType outType) { - this(null, containingDeclaration, annotations, modality, visibility, isVar, receiverType, name, inType, outType); + this(null, containingDeclaration, annotations, modality, visibility, isVar, receiverType, expectedThisObject, name, inType, outType); } private PropertyDescriptor( @NotNull PropertyDescriptor original, @Nullable JetType receiverType, + @NotNull ReceiverDescriptor expectedThisObject, @Nullable JetType inType, @NotNull JetType outType) { this( @@ -77,6 +83,7 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab original.getVisibility(), original.isVar, receiverType, + expectedThisObject, original.getName(), inType, outType); @@ -95,10 +102,16 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab } @NotNull - public ReceiverDescriptor getReceiver() { + public ReceiverDescriptor getReceiverParameter() { return receiver; } + @NotNull + @Override + public ReceiverDescriptor getExpectedThisObject() { + return expectedThisObject; + } + @NotNull @Override public JetType getReturnType() { @@ -132,7 +145,6 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab return setter; } - @NotNull @Override public PropertyDescriptor substitute(TypeSubstitutor substitutor) { JetType originalInType = getInType(); @@ -142,9 +154,18 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab if (inType == null && outType == null) { return null; // TODO : tell the user that the property was projected out } + JetType substitutedReceiverType; + if (receiver.exists()) { + substitutedReceiverType = substitutor.substitute(receiver.getType(), Variance.IN_VARIANCE); + if (substitutedReceiverType == null) return null; + } + else { + substitutedReceiverType = null; + } return new PropertyDescriptor( this, - receiver.exists() ? substitutor.substitute(receiver.getType(), Variance.IN_VARIANCE) : null, + substitutedReceiverType, + expectedThisObject.exists() ? new TransientReceiver(substitutor.substitute(expectedThisObject.getType(), Variance.IN_VARIANCE)) : expectedThisObject, inType, outType ); @@ -171,6 +192,7 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab return overriddenProperties; } + @NotNull @Override public PropertyDescriptor copy(DeclarationDescriptor newOwner, boolean makeNonAbstract) { @@ -178,7 +200,9 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab newOwner, Lists.newArrayList(getAnnotations()), DescriptorUtils.convertModality(modality, makeNonAbstract), visibility, isVar, - receiver.exists() ? receiver.getType() : null, getName(), getInType(), getOutType()); + receiver.exists() ? receiver.getType() : null, + expectedThisObject, + getName(), getInType(), getOutType()); PropertyGetterDescriptor newGetter = getter == null ? null : new PropertyGetterDescriptor( propertyDescriptor, Lists.newArrayList(getter.getAnnotations()), DescriptorUtils.convertModality(getter.getModality(), makeNonAbstract), getter.getVisibility(), diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java index 747a27e64a7..01bde2bf062 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java @@ -33,12 +33,6 @@ public class PropertyGetterDescriptor extends PropertyAccessorDescriptor { overriddenGetters.add(overriddenGetter); } - @NotNull - @Override - public ReceiverDescriptor getReceiver() { - return getCorrespondingProperty().getReceiver(); - } - @NotNull @Override public List getValueParameters() { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java index 13752d9743c..d5f2038a282 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java @@ -3,7 +3,6 @@ package org.jetbrains.jet.lang.descriptors; import com.google.common.collect.Sets; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; -import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; @@ -42,12 +41,6 @@ public class PropertySetterDescriptor extends PropertyAccessorDescriptor { overriddenSetters.add(overriddenSetter); } - @NotNull - @Override - public ReceiverDescriptor getReceiver() { - return getCorrespondingProperty().getReceiver(); - } - @NotNull @Override public List getValueParameters() { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableAsFunctionDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableAsFunctionDescriptor.java index 88462653cfc..25b713cd607 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableAsFunctionDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableAsFunctionDescriptor.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.descriptors; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; @@ -16,7 +17,7 @@ public class VariableAsFunctionDescriptor extends FunctionDescriptorImpl { assert outType != null; assert JetStandardClasses.isFunctionType(outType); VariableAsFunctionDescriptor result = new VariableAsFunctionDescriptor(variableDescriptor); - result.initialize(JetStandardClasses.getReceiverType(outType), Collections.emptyList(), JetStandardClasses.getValueParameters(result, outType), JetStandardClasses.getReturnType(outType), Modality.FINAL, Visibility.LOCAL); + result.initialize(JetStandardClasses.getReceiverType(outType), ReceiverDescriptor.NO_RECEIVER, Collections.emptyList(), JetStandardClasses.getValueParameters(result, outType), JetStandardClasses.getReturnType(outType), Modality.FINAL, Visibility.LOCAL); return result; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptor.java index fc883d59508..4490b83fc96 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptor.java @@ -26,7 +26,6 @@ public interface VariableDescriptor extends CallableDescriptor { @NotNull DeclarationDescriptor getContainingDeclaration(); - @NotNull @Override VariableDescriptor substitute(TypeSubstitutor substitutor); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java index c941fae9605..6daefbce285 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java @@ -74,7 +74,13 @@ public abstract class VariableDescriptorImpl extends DeclarationDescriptorImpl i @NotNull @Override - public ReceiverDescriptor getReceiver() { + public ReceiverDescriptor getReceiverParameter() { + return ReceiverDescriptor.NO_RECEIVER; + } + + @NotNull + @Override + public ReceiverDescriptor getExpectedThisObject() { return ReceiverDescriptor.NO_RECEIVER; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/AmbiguousDescriptorDiagnosticFactory.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/AmbiguousDescriptorDiagnosticFactory.java index f3cc1e2a67d..b9d4050f915 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/AmbiguousDescriptorDiagnosticFactory.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/AmbiguousDescriptorDiagnosticFactory.java @@ -1,7 +1,8 @@ package org.jetbrains.jet.lang.diagnostics; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.CallableDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.resolve.DescriptorRenderer; import java.util.Collection; @@ -9,7 +10,7 @@ import java.util.Collection; /** * @author abreslav */ -public class AmbiguousDescriptorDiagnosticFactory extends ParameterizedDiagnosticFactory1> { +public class AmbiguousDescriptorDiagnosticFactory extends ParameterizedDiagnosticFactory1>> { public static AmbiguousDescriptorDiagnosticFactory create(String messageTemplate) { return new AmbiguousDescriptorDiagnosticFactory(messageTemplate); } @@ -19,10 +20,10 @@ public class AmbiguousDescriptorDiagnosticFactory extends ParameterizedDiagnosti } @Override - protected String makeMessageFor(@NotNull Collection argument) { + protected String makeMessageFor(@NotNull Collection> argument) { StringBuilder stringBuilder = new StringBuilder("\n"); - for (CallableDescriptor descriptor : argument) { - stringBuilder.append(DescriptorRenderer.TEXT.render(descriptor)).append("\n"); + for (ResolvedCall call : argument) { + stringBuilder.append(DescriptorRenderer.TEXT.render(call.getResultingDescriptor())).append("\n"); } return stringBuilder.toString(); } 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 7cff43d00f5..b91883012bc 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -59,7 +59,7 @@ public interface Errors { return sb.toString(); } }; - ParameterizedDiagnosticFactory1 ILLEGAL_MODIFIER = ParameterizedDiagnosticFactory1.create(ERROR, "Illegal modifier ''{0}''"); + DiagnosticWithParameterFactory ILLEGAL_MODIFIER = DiagnosticWithParameterFactory.create(ERROR, "Illegal modifier ''{0}''", DiagnosticParameters.MODIFIER); PsiElementOnlyDiagnosticFactory2 REDUNDANT_MODIFIER = new PsiElementOnlyDiagnosticFactory2(Severity.WARNING, "Modifier {0} is redundant because {1} is present") { @NotNull @@ -69,6 +69,7 @@ public interface Errors { } }; DiagnosticWithParameterFactory REDUNDANT_MODIFIER_IN_TRAIT = DiagnosticWithParameterFactory.create(WARNING, "Modifier ''{0}'' is redundant in trait", DiagnosticParameters.MODIFIER); + DiagnosticWithParameterFactory REDUNDANT_MODIFIER_IN_GETTER = DiagnosticWithParameterFactory.create(WARNING, "Visibility modifiers are redundant in getter", DiagnosticParameters.MODIFIER); SimplePsiElementOnlyDiagnosticFactory TRAIT_CAN_NOT_BE_FINAL = SimplePsiElementOnlyDiagnosticFactory.create(ERROR, "Trait can not be final"); SimpleDiagnosticFactory SAFE_CALLS_ARE_NOT_ALLOWED_ON_NAMESPACES = SimpleDiagnosticFactory.create(ERROR, "Safe calls are not allowed on namespaces"); SimpleDiagnosticFactory TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM = SimpleDiagnosticFactory.create(ERROR, "Type checking has run into a recursive problem"); // TODO: message @@ -94,6 +95,8 @@ public interface Errors { DiagnosticWithParameterFactory ABSTRACT_PROPERTY_WITH_INITIALIZER = DiagnosticWithParameterFactory.create(ERROR, "Property with initializer cannot be abstract", DiagnosticParameters.TYPE); DiagnosticWithParameterFactory ABSTRACT_PROPERTY_WITH_GETTER = DiagnosticWithParameterFactory.create(ERROR, "Property with getter implementation cannot be abstract", DiagnosticParameters.TYPE); DiagnosticWithParameterFactory ABSTRACT_PROPERTY_WITH_SETTER = DiagnosticWithParameterFactory.create(ERROR, "Property with setter implementation cannot be abstract", DiagnosticParameters.TYPE); + + DiagnosticWithParameterFactory GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY = DiagnosticWithParameterFactory.create(ERROR, "Getter visibility must be the same as property visibility", DiagnosticParameters.MODIFIER); SimpleDiagnosticFactory BACKING_FIELD_IN_TRAIT = SimpleDiagnosticFactory.create(ERROR, "Property in a trait cannot have a backing field"); SimpleDiagnosticFactory MUST_BE_INITIALIZED = SimpleDiagnosticFactory.create(ERROR, "Property must be initialized"); SimplePsiElementOnlyDiagnosticFactory MUST_BE_INITIALIZED_OR_BE_ABSTRACT = SimplePsiElementOnlyDiagnosticFactory.create(ERROR, "Property must be initialized or be abstract"); @@ -106,22 +109,21 @@ public interface Errors { return super.on(elementToBlame, textRangeToMark, s, classDescriptor, aClass).add(DiagnosticParameters.CLASS, aClass); } }; - PsiElementOnlyDiagnosticFactory3 ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS = new PsiElementOnlyDiagnosticFactory3(ERROR, "Abstract function {0} in non-abstract class {1}") { + PsiElementOnlyDiagnosticFactory3 ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS = new PsiElementOnlyDiagnosticFactory3(ERROR, "Abstract function {0} in non-abstract class {1}") { @NotNull - public DiagnosticWithPsiElement on(@NotNull JetFunctionOrPropertyAccessor elementToBlame, @NotNull ASTNode nodeToMark, @NotNull String s, @NotNull ClassDescriptor classDescriptor, @NotNull JetClass modifierListOwner) { + public DiagnosticWithPsiElement on(@NotNull JetFunction elementToBlame, @NotNull ASTNode nodeToMark, @NotNull String s, @NotNull ClassDescriptor classDescriptor, @NotNull JetClass modifierListOwner) { return super.on(elementToBlame, nodeToMark, s, classDescriptor, modifierListOwner).add(DiagnosticParameters.CLASS, modifierListOwner); } }; - PsiElementOnlyDiagnosticFactory1 ABSTRACT_FUNCTION_WITH_BODY = PsiElementOnlyDiagnosticFactory1.create(ERROR, "A function {0} with body cannot be abstract"); - PsiElementOnlyDiagnosticFactory1 NON_ABSTRACT_FUNCTION_WITH_NO_BODY = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Method {0} without a body must be abstract"); + PsiElementOnlyDiagnosticFactory1 ABSTRACT_FUNCTION_WITH_BODY = PsiElementOnlyDiagnosticFactory1.create(ERROR, "A function {0} with body cannot be abstract"); + PsiElementOnlyDiagnosticFactory1 NON_ABSTRACT_FUNCTION_WITH_NO_BODY = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Method {0} without a body must be abstract"); PsiElementOnlyDiagnosticFactory1 NON_MEMBER_ABSTRACT_FUNCTION = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Function {0} is not a class or trait member and cannot be abstract"); - SimplePsiElementOnlyDiagnosticFactory NON_MEMBER_ABSTRACT_ACCESSOR = SimplePsiElementOnlyDiagnosticFactory.create(ERROR, "This property is not a class or trait member and thus cannot have abstract accessors"); // TODO : Better message - PsiElementOnlyDiagnosticFactory1 NON_MEMBER_FUNCTION_NO_BODY = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Function {0} must have a body"); + PsiElementOnlyDiagnosticFactory1 NON_MEMBER_FUNCTION_NO_BODY = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Function {0} must have a body"); DiagnosticWithParameterFactory NON_FINAL_MEMBER_IN_FINAL_CLASS = DiagnosticWithParameterFactory.create(ERROR, "Non final member in a final class", DiagnosticParameters.CLASS); - DiagnosticWithParameterFactory NON_FINAL_ACCESSOR_OF_FINAL_PROPERTY = DiagnosticWithParameterFactory.create(ERROR, "Non final accessor of a final property", DiagnosticParameters.PROPERTY); - DiagnosticWithParameterFactory ABSTRACT_ACCESSOR_OF_NON_ABSTRACT_PROPERTY = DiagnosticWithParameterFactory.create(ERROR, "Abstract accessor of a final property", DiagnosticParameters.PROPERTY); + + DiagnosticWithParameterFactory PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE = DiagnosticWithParameterFactory.create(ERROR, "Public member should specify a type", DiagnosticParameters.TYPE); SimpleDiagnosticFactory PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT = SimpleDiagnosticFactory.create(ERROR, "Projections are not allowed on type arguments of functions and properties"); // TODO : better positioning SimpleDiagnosticFactory SUPERTYPE_NOT_INITIALIZED = SimpleDiagnosticFactory.create(ERROR, "This type has a constructor, and thus must be initialized here"); @@ -130,7 +132,7 @@ public interface Errors { SimpleDiagnosticFactory BY_IN_SECONDARY_CONSTRUCTOR = SimpleDiagnosticFactory.create(ERROR, "'by'-clause is only supported for primary constructors"); SimpleDiagnosticFactory INITIALIZER_WITH_NO_ARGUMENTS = SimpleDiagnosticFactory.create(ERROR, "Constructor arguments required"); SimpleDiagnosticFactory MANY_CALLS_TO_THIS = SimpleDiagnosticFactory.create(ERROR, "Only one call to 'this(...)' is allowed"); - PsiElementOnlyDiagnosticFactory1 NOTHING_TO_OVERRIDE = PsiElementOnlyDiagnosticFactory1.create(ERROR, "{0} overrides nothing", DescriptorRenderer.TEXT); + PsiElementOnlyDiagnosticFactory1 NOTHING_TO_OVERRIDE = PsiElementOnlyDiagnosticFactory1.create(ERROR, "{0} overrides nothing", DescriptorRenderer.TEXT); PsiElementOnlyDiagnosticFactory1 PRIMARY_CONSTRUCTOR_MISSING_STATEFUL_PROPERTY = PsiElementOnlyDiagnosticFactory1.create(ERROR, "This class must have a primary constructor, because property {0} has a backing field"); ParameterizedDiagnosticFactory1 PRIMARY_CONSTRUCTOR_MISSING_SUPER_CONSTRUCTOR_CALL = new ParameterizedDiagnosticFactory1(ERROR, "Class {0} must have a constructor in order to be able to initialize supertypes") { @Override @@ -141,7 +143,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"); @@ -189,6 +190,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"); @@ -219,6 +221,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"); @@ -237,7 +240,7 @@ public interface Errors { return constraintOwner.getName(); } }; - ParameterizedDiagnosticFactory2 AUTOCAST_IMPOSSIBLE = ParameterizedDiagnosticFactory2.create(ERROR, "Automatic cast to {0} is impossible, because variable {1} is mutable", NAME); + ParameterizedDiagnosticFactory2 AUTOCAST_IMPOSSIBLE = ParameterizedDiagnosticFactory2.create(ERROR, "Automatic cast to {0} is impossible, because {1} could have changed since the is-check"); ParameterizedDiagnosticFactory2 TYPE_MISMATCH_IN_FOR_LOOP = ParameterizedDiagnosticFactory2.create(ERROR, "The loop iterates over values of type {0} but the parameter is declared to be {1}"); ParameterizedDiagnosticFactory1 TYPE_MISMATCH_IN_CONDITION = ParameterizedDiagnosticFactory1.create(ERROR, "Condition must be of type Boolean, but was of type {0}"); @@ -348,10 +351,10 @@ public interface Errors { }; ParameterizedDiagnosticFactory3 RESULT_TYPE_MISMATCH = ParameterizedDiagnosticFactory3.create(ERROR, "{0} must return {1} but returns {2}"); - ParameterizedDiagnosticFactory3 UNSAFE_INFIX_CALL = ParameterizedDiagnosticFactory3.create(ERROR, "Infix call corresponds to a dot-qualified call ''{0}.{1}({2})' which is not allowed on a nullable receiver ''{0}''. Use '?.'-qualified call instead"); + ParameterizedDiagnosticFactory3 UNSAFE_INFIX_CALL = ParameterizedDiagnosticFactory3.create(ERROR, "Infix call corresponds to a dot-qualified call ''{0}.{1}({2})'' which is not allowed on a nullable receiver ''{0}''. Use '?.'-qualified call instead"); - ParameterizedDiagnosticFactory1> OVERLOAD_RESOLUTION_AMBIGUITY = new AmbiguousDescriptorDiagnosticFactory("Overload resolution ambiguity: {0}"); - ParameterizedDiagnosticFactory1> NONE_APPLICABLE = new AmbiguousDescriptorDiagnosticFactory("None of the following functions can be called with the arguments supplied: {0}"); + AmbiguousDescriptorDiagnosticFactory OVERLOAD_RESOLUTION_AMBIGUITY = new AmbiguousDescriptorDiagnosticFactory("Overload resolution ambiguity: {0}"); + AmbiguousDescriptorDiagnosticFactory NONE_APPLICABLE = new AmbiguousDescriptorDiagnosticFactory("None of the following functions can be called with the arguments supplied: {0}"); ParameterizedDiagnosticFactory1 NO_VALUE_FOR_PARAMETER = ParameterizedDiagnosticFactory1.create(ERROR, "No value passed for parameter {0}", DescriptorRenderer.TEXT); ParameterizedDiagnosticFactory1 MISSING_RECEIVER = ParameterizedDiagnosticFactory1.create(ERROR, "A receiver of type {0} is required"); SimpleDiagnosticFactory NO_RECEIVER_ADMITTED = SimpleDiagnosticFactory.create(ERROR, "No receiver can be passed to this function or property"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/Call.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/Call.java index 6813fdfdbaf..ebc74358f2f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/Call.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/Call.java @@ -1,7 +1,10 @@ package org.jetbrains.jet.lang.psi; +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import java.util.List; @@ -9,6 +12,14 @@ import java.util.List; * @author abreslav */ public interface Call { + + // SAFE_ACCESS or DOT or so + @Nullable + ASTNode getCallOperationNode(); + + @NotNull + ReceiverDescriptor getExplicitReceiver(); + @Nullable JetExpression getCalleeExpression(); @@ -26,4 +37,10 @@ public interface Call { @Nullable JetTypeArgumentList getTypeArgumentList(); + + @NotNull + ASTNode getCallNode(); + + @Nullable + PsiElement getCallElement(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallElement.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallElement.java index a9a1a38d6e0..5fffa5f8131 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallElement.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallElement.java @@ -9,6 +9,22 @@ import java.util.List; /** * @author abreslav */ -public interface JetCallElement extends PsiElement, Call { +public interface JetCallElement extends PsiElement { + @Nullable + JetExpression getCalleeExpression(); + @Nullable + JetValueArgumentList getValueArgumentList(); + + @NotNull + List getValueArguments(); + + @NotNull + List getFunctionLiteralArguments(); + + @NotNull + List getTypeArguments(); + + @Nullable + JetTypeArgumentList getTypeArgumentList(); } 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/JetFunction.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunction.java index 09fee5a8b43..52c987ea24f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunction.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunction.java @@ -14,7 +14,7 @@ import java.util.List; /** * @author abreslav */ -abstract public class JetFunction extends JetTypeParameterListOwner implements JetFunctionOrPropertyAccessor { +abstract public class JetFunction extends JetTypeParameterListOwner implements JetDeclarationWithBody, JetModifierListOwner { public JetFunction(@NotNull ASTNode node) { super(node); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunctionOrPropertyAccessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunctionOrPropertyAccessor.java deleted file mode 100644 index 9ce62477999..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunctionOrPropertyAccessor.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.jetbrains.jet.lang.psi; - -/** - * @author svtk - */ -public interface JetFunctionOrPropertyAccessor extends JetDeclarationWithBody, JetModifierListOwner { -} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPropertyAccessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPropertyAccessor.java index a1aa5e418c9..6cf67771acb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPropertyAccessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPropertyAccessor.java @@ -13,7 +13,7 @@ import java.util.List; /** * @author max */ -public class JetPropertyAccessor extends JetDeclaration implements JetFunctionOrPropertyAccessor { +public class JetPropertyAccessor extends JetDeclaration implements JetDeclarationWithBody, JetModifierListOwner { public JetPropertyAccessor(@NotNull ASTNode node) { super(node); } 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/resolve/AnnotationResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java index 813118617a6..512f9f192c3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java @@ -9,12 +9,11 @@ import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.psi.JetAnnotationEntry; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetModifierList; +import org.jetbrains.jet.lang.resolve.calls.CallResolver; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; -import org.jetbrains.jet.lang.types.ErrorUtils; -import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.JetTypeInferrer; +import org.jetbrains.jet.lang.types.*; import java.util.Collections; import java.util.List; @@ -27,11 +26,15 @@ import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE; public class AnnotationResolver { private final BindingTrace trace; - private final JetTypeInferrer typeInferrer; +// private final JetTypeInferrer typeInferrer; + private final CallResolver callResolver; +// private final JetTypeInferrer.Services services; public AnnotationResolver(JetSemanticServices semanticServices, BindingTrace trace) { - this.typeInferrer = new JetTypeInferrer(JetFlowInformationProvider.THROW_EXCEPTION, semanticServices); this.trace = trace; +// this.typeInferrer = new JetTypeInferrer(JetFlowInformationProvider.THROW_EXCEPTION, semanticServices); +// this.services = typeInferrer.getServices(this.trace); + this.callResolver = new CallResolver(semanticServices, new JetTypeInferrer(semanticServices), DataFlowInfo.getEmpty()); } @NotNull @@ -47,7 +50,7 @@ public class AnnotationResolver { } public void resolveAnnotationStub(@NotNull JetScope scope, @NotNull JetAnnotationEntry entryElement, @NotNull AnnotationDescriptor descriptor) { - JetType jetType = typeInferrer.getCallResolver().resolveCall(trace, scope, ReceiverDescriptor.NO_RECEIVER, entryElement, NO_EXPECTED_TYPE); + JetType jetType = callResolver.resolveCall(trace, scope, CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, entryElement), NO_EXPECTED_TYPE); descriptor.setAnnotationType(jetType == null ? ErrorUtils.createErrorType("Unresolved annotation type") : jetType); } @@ -112,4 +115,4 @@ public class AnnotationResolver { } return createAnnotationStubs(modifierList.getAnnotationEntries()); } -} \ No newline at end of file +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index c4b719d139a..e5d49d0c837 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -6,9 +6,9 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.scopes.JetScope; -import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.DeferredType; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.util.CommonSuppliers; @@ -20,15 +20,16 @@ import java.util.Collection; * @author abreslav */ public interface BindingContext { - WritableSlice RECEIVER = Slices.createSimpleSlice("RECEIVER"); - WritableSlice ANNOTATION = Slices.createSimpleSlice("ANNOTATION"); + WritableSlice> COMPILE_TIME_VALUE = Slices.createSimpleSlice("COMPILE_TIME_VALUE"); WritableSlice TYPE = Slices.createSimpleSlice("TYPE"); WritableSlice EXPRESSION_TYPE = new BasicWritableSlice("EXPRESSION_TYPE", RewritePolicy.DO_NOTHING); WritableSlice REFERENCE_TARGET = new BasicWritableSlice("REFERENCE_TARGET", RewritePolicy.DO_NOTHING); - WritableSlice> AMBIGUOUS_REFERENCE_TARGET = new BasicWritableSlice>("AMBIGUOUS_REFERENCE_TARGET", RewritePolicy.DO_NOTHING); + WritableSlice> RESOLVED_CALL = new BasicWritableSlice>("RESOLVED_CALL", RewritePolicy.DO_NOTHING); + + WritableSlice>> AMBIGUOUS_REFERENCE_TARGET = new BasicWritableSlice>>("AMBIGUOUS_REFERENCE_TARGET", RewritePolicy.DO_NOTHING); WritableSlice LOOP_RANGE_ITERATOR = Slices.createSimpleSlice("LOOP_RANGE_ITERATOR"); WritableSlice LOOP_RANGE_HAS_NEXT = Slices.createSimpleSlice("LOOP_RANGE_HAS_NEXT"); @@ -43,9 +44,12 @@ public interface BindingContext { WritableSlice PROCESSED = Slices.createSimpleSetSlice("PROCESSED"); WritableSlice STATEMENT = Slices.createRemovableSetSlice("STATEMENT"); WritableSlice DELEGATED = Slices.createRemovableSetSlice("DELEGATED"); + + WritableSlice MUST_BE_WRAPPED_IN_A_REF = Slices.createSimpleSetSlice("MUST_BE_WRAPPED_IN_A_REF"); enum DeferredTypeKey {DEFERRED_TYPE_KEY} WritableSlice> DEFERRED_TYPES = Slices.createSimpleSlice("DEFERRED_TYPES"); + WritableSlice DEFERRED_TYPE = new CollectionSliceWrapper(DEFERRED_TYPES, CommonSuppliers.getArrayListSupplier()); WritableSlice BACKING_FIELD_REQUIRED = new Slices.SetSlice("BACKING_FIELD_REQUIRED", RewritePolicy.DO_NOTHING) { 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 c8255af2f9d..e4820f5044c 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() { @@ -172,7 +172,9 @@ public class BodyResolver { JetTypeReference typeReference = call.getTypeReference(); if (typeReference != null) { if (descriptor.getUnsubstitutedPrimaryConstructor() != null) { - JetType supertype = typeInferrer.getCallResolver().resolveCall(context.getTrace(), scopeForConstructor, ReceiverDescriptor.NO_RECEIVER, call, NO_EXPECTED_TYPE); + JetType supertype = typeInferrer.getCallResolver().resolveCall( + context.getTrace(), scopeForConstructor, + CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call), NO_EXPECTED_TYPE); if (supertype != null) { recordSupertype(typeReference, supertype); ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); @@ -290,7 +292,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 +318,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"; @@ -334,7 +336,8 @@ public class BodyResolver { public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) { JetTypeReference typeReference = call.getTypeReference(); if (typeReference != null) { - typeInferrerForInitializers.getCallResolver().resolveCall(context.getTrace(), functionInnerScope, null, call, NO_EXPECTED_TYPE); + typeInferrerForInitializers.getCallResolver().resolveCall(context.getTrace(), functionInnerScope, + CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call), NO_EXPECTED_TYPE); } } @@ -346,7 +349,7 @@ public class BodyResolver { typeInferrerForInitializers.getCallResolver().resolveCall(context.getTrace(), functionInnerScope, - ReceiverDescriptor.NO_RECEIVER, call, NO_EXPECTED_TYPE); + CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call), NO_EXPECTED_TYPE); // call.getThisReference(), // classDescriptor, // classDescriptor.getDefaultType(), @@ -377,11 +380,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()); } } @@ -456,7 +459,7 @@ public class BodyResolver { for (TypeParameterDescriptor typeParameterDescriptor : propertyDescriptor.getTypeParameters()) { result.addTypeParameterDescriptor(typeParameterDescriptor); } - ReceiverDescriptor receiver = propertyDescriptor.getReceiver(); + ReceiverDescriptor receiver = propertyDescriptor.getReceiverParameter(); if (receiver.exists()) { result.setImplicitReceiver(receiver); } @@ -516,8 +519,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 +555,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 1672a1329c8..ecffbcc9abc 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); } }); } @@ -195,6 +195,7 @@ public class ClassDescriptorResolver { Visibility visibility = resolveVisibilityFromModifiers(function.getModifierList()); functionDescriptor.initialize( receiverType, + DescriptorUtils.getExpectedThisObjectIfNeeded(containingDescriptor), typeParameterDescriptors, valueParameterDescriptors, returnType, @@ -438,6 +439,7 @@ public class ClassDescriptorResolver { resolveVisibilityFromModifiers(objectDeclaration.getModifierList()), false, null, + DescriptorUtils.getExpectedThisObjectIfNeeded(containingDeclaration), JetPsiUtil.safeName(objectDeclaration.getName()), null, classDescriptor.getDefaultType()); @@ -481,17 +483,7 @@ public class ClassDescriptorResolver { JetType type = getVariableType(scopeWithTypeParameters, property, true); - boolean hasBody = property.getInitializer() != null; - if (!hasBody) { - JetPropertyAccessor getter = property.getGetter(); - if (getter != null && getter.getBodyExpression() != null) { - hasBody = true; - } - JetPropertyAccessor setter = property.getSetter(); - if (!hasBody && setter != null && setter.getBodyExpression() != null) { - hasBody = true; - } - } + boolean hasBody = hasBody(property); Modality defaultModality = getDefaultModality(containingDeclaration, hasBody); PropertyDescriptor propertyDescriptor = new PropertyDescriptor( containingDeclaration, @@ -500,6 +492,7 @@ public class ClassDescriptorResolver { resolveVisibilityFromModifiers(property.getModifierList()), isVar, receiverType, + DescriptorUtils.getExpectedThisObjectIfNeeded(containingDeclaration), JetPsiUtil.safeName(property.getName()), isVar ? type : null, type); @@ -513,6 +506,21 @@ public class ClassDescriptorResolver { return propertyDescriptor; } + /*package*/ static boolean hasBody(JetProperty property) { + boolean hasBody = property.getInitializer() != null; + if (!hasBody) { + JetPropertyAccessor getter = property.getGetter(); + if (getter != null && getter.getBodyExpression() != null) { + hasBody = true; + } + JetPropertyAccessor setter = property.getSetter(); + if (!hasBody && setter != null && setter.getBodyExpression() != null) { + hasBody = true; + } + } + return hasBody; + } + @NotNull private JetType getVariableType(@NotNull final JetScope scope, @NotNull final JetProperty property, boolean allowDeferred) { // TODO : receiver? @@ -532,8 +540,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) { @@ -756,6 +764,7 @@ public class ClassDescriptorResolver { resolveVisibilityFromModifiers(parameter.getModifierList()), isMutable, null, + DescriptorUtils.getExpectedThisObjectIfNeeded(classDescriptor), name == null ? "" : name, isMutable ? type : null, type); 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..d4f0dec17dd --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java @@ -0,0 +1,114 @@ +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)); + } + } + } + }); + } + } + + private void checkProperty(JetProperty property) { + JetExpression initializer = property.getInitializer(); + if (initializer == null) return; + context.getClassDescriptorResolver().computeFlowData(property, initializer); + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java index 7a840513fdb..0d1cc073e49 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java @@ -117,9 +117,9 @@ public class DeclarationResolver { @Override public void visitEnumEntry(JetEnumEntry enumEntry) { if (enumEntry.getPrimaryConstructorParameterList() == null) { - PropertyDescriptor propertyDescriptor = context.getClassDescriptorResolver().resolveObjectDeclarationAsPropertyDescriptor(namespaceLike, enumEntry, context.getClasses().get(enumEntry)); MutableClassDescriptor classObjectDescriptor = ((MutableClassDescriptor) namespaceLike).getClassObjectDescriptor(); assert classObjectDescriptor != null; + PropertyDescriptor propertyDescriptor = context.getClassDescriptorResolver().resolveObjectDeclarationAsPropertyDescriptor(classObjectDescriptor, enumEntry, context.getClasses().get(enumEntry)); classObjectDescriptor.addPropertyDescriptor(propertyDescriptor); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java index 97efea7d0d9..acebd21b8e6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.lang.resolve; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.intellij.lang.ASTNode; import com.intellij.openapi.util.Pair; @@ -10,7 +11,6 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.types.DeferredType; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lexer.JetKeywordToken; @@ -20,7 +20,6 @@ import org.jetbrains.jet.lexer.JetTokens; import java.util.ArrayList; import java.util.Collection; import java.util.Map; -import java.util.Set; import static org.jetbrains.jet.lang.diagnostics.Errors.*; @@ -114,7 +113,7 @@ public class DeclarationsChecker { private void checkObject(JetObjectDeclaration objectDeclaration, MutableClassDescriptor classDescriptor) { - checkIllegalInThisContextModifiers(objectDeclaration.getModifierList(), JetTokens.ABSTRACT_KEYWORD, JetTokens.OPEN_KEYWORD, JetTokens.OVERRIDE_KEYWORD); + checkIllegalInThisContextModifiers(objectDeclaration.getModifierList(), Sets.newHashSet(JetTokens.ABSTRACT_KEYWORD, JetTokens.OPEN_KEYWORD, JetTokens.OVERRIDE_KEYWORD)); } private void checkOpenMembers(JetClass aClass, MutableClassDescriptor classDescriptor) { @@ -122,7 +121,9 @@ public class DeclarationsChecker { JetNamedDeclaration member = (JetNamedDeclaration) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, memberDescriptor); if (member != null && classDescriptor.getModality() == Modality.FINAL && member.hasModifier(JetTokens.OPEN_KEYWORD)) { - ASTNode openModifierNode = member.getModifierList().getModifierNode(JetTokens.OPEN_KEYWORD); + JetModifierList modifierList = member.getModifierList(); + assert modifierList != null; + ASTNode openModifierNode = modifierList.getModifierNode(JetTokens.OPEN_KEYWORD); context.getTrace().report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member, openModifierNode, aClass)); } } @@ -136,6 +137,29 @@ public class DeclarationsChecker { checkPropertyAbstractness(property, propertyDescriptor, classDescriptor); checkPropertyInitializer(property, propertyDescriptor, classDescriptor); checkAccessors(property, propertyDescriptor); + checkDeclaredTypeInPublicMember(property, propertyDescriptor); + } + + private void checkDeclaredTypeInPublicMember(JetNamedDeclaration member, CallableMemberDescriptor memberDescriptor) { + PsiElement nameIdentifier = member.getNameIdentifier(); + boolean hasDeferredType; + if (member instanceof JetProperty) { + hasDeferredType = ((JetProperty) member).getPropertyTypeRef() == null && ClassDescriptorResolver.hasBody((JetProperty) member); + } + else { + assert member instanceof JetFunction; + JetFunction function = (JetFunction) member; + hasDeferredType = function.getReturnTypeRef() == null && function.getBodyExpression() != null && !function.hasBlockBody(); + } + if ((memberDescriptor.getVisibility() == Visibility.PUBLIC || memberDescriptor.getVisibility() == Visibility.PROTECTED) && + hasDeferredType && nameIdentifier != null) { + + JetType returnType = memberDescriptor.getReturnType(); + if (returnType instanceof DeferredType) { + returnType = ((DeferredType) returnType).getActualType(); + } + context.getTrace().report(PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE.on(member, nameIdentifier, returnType)); + } } private void checkPropertyAbstractness(JetProperty property, PropertyDescriptor propertyDescriptor, ClassDescriptor classDescriptor) { @@ -225,24 +249,13 @@ public class DeclarationsChecker { } } - protected void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) { + protected void checkFunction(JetNamedFunction function, FunctionDescriptor functionDescriptor) { DeclarationDescriptor containingDescriptor = functionDescriptor.getContainingDeclaration(); - PsiElement nameIdentifier; - boolean isPropertyAccessor = false; - if (function instanceof JetNamedFunction) { - nameIdentifier = ((JetNamedFunction) function).getNameIdentifier(); - } - else if (function instanceof JetPropertyAccessor) { - isPropertyAccessor = true; - nameIdentifier = ((JetPropertyAccessor) function).getNamePlaceholder(); - } - else { - throw new UnsupportedOperationException(); - } - JetFunctionOrPropertyAccessor functionOrPropertyAccessor = (JetFunctionOrPropertyAccessor) function; - JetModifierList modifierList = functionOrPropertyAccessor.getModifierList(); + PsiElement nameIdentifier = function.getNameIdentifier(); + JetModifierList modifierList = function.getModifierList(); ASTNode abstractNode = modifierList != null ? modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD) : null; boolean hasAbstractModifier = abstractNode != null; + checkDeclaredTypeInPublicMember(function, functionDescriptor); if (containingDescriptor instanceof ClassDescriptor) { ClassDescriptor classDescriptor = (ClassDescriptor) containingDescriptor; boolean inTrait = classDescriptor.getKind() == ClassKind.TRAIT; @@ -251,46 +264,45 @@ public class DeclarationsChecker { if (hasAbstractModifier && !inAbstractClass && !inTrait && !inEnum) { PsiElement classElement = context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, classDescriptor); assert classElement instanceof JetClass; - context.getTrace().report(ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS.on(functionOrPropertyAccessor, abstractNode, functionDescriptor.getName(), classDescriptor, (JetClass) classElement)); + context.getTrace().report(ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS.on(function, abstractNode, functionDescriptor.getName(), classDescriptor, (JetClass) classElement)); } - if (hasAbstractModifier && inTrait && !isPropertyAccessor) { + if (hasAbstractModifier && inTrait) { context.getTrace().report(REDUNDANT_MODIFIER_IN_TRAIT.on(modifierList, abstractNode, JetTokens.ABSTRACT_KEYWORD)); } if (function.getBodyExpression() != null && hasAbstractModifier) { - context.getTrace().report(ABSTRACT_FUNCTION_WITH_BODY.on(functionOrPropertyAccessor, abstractNode, functionDescriptor)); + context.getTrace().report(ABSTRACT_FUNCTION_WITH_BODY.on(function, abstractNode, functionDescriptor)); } - if (function.getBodyExpression() == null && !hasAbstractModifier && !inTrait && nameIdentifier != null && !isPropertyAccessor) { - context.getTrace().report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(functionOrPropertyAccessor, nameIdentifier, functionDescriptor)); + if (function.getBodyExpression() == null && !hasAbstractModifier && !inTrait && nameIdentifier != null) { + context.getTrace().report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(function, nameIdentifier, functionDescriptor)); } return; } if (hasAbstractModifier) { - if (!isPropertyAccessor) { - context.getTrace().report(NON_MEMBER_ABSTRACT_FUNCTION.on(functionOrPropertyAccessor, abstractNode, functionDescriptor)); - } - else { - context.getTrace().report(NON_MEMBER_ABSTRACT_ACCESSOR.on(functionOrPropertyAccessor, abstractNode)); - } + context.getTrace().report(NON_MEMBER_ABSTRACT_FUNCTION.on(function, abstractNode, functionDescriptor)); } - if (function.getBodyExpression() == null && !hasAbstractModifier && nameIdentifier != null && !isPropertyAccessor) { - context.getTrace().report(NON_MEMBER_FUNCTION_NO_BODY.on(functionOrPropertyAccessor, nameIdentifier, functionDescriptor)); + if (function.getBodyExpression() == null && !hasAbstractModifier && nameIdentifier != null) { + context.getTrace().report(NON_MEMBER_FUNCTION_NO_BODY.on(function, nameIdentifier, functionDescriptor)); } } private void checkAccessors(JetProperty property, PropertyDescriptor propertyDescriptor) { for (JetPropertyAccessor accessor : property.getAccessors()) { - PropertyAccessorDescriptor accessorDescriptor = accessor.isGetter() - ? propertyDescriptor.getGetter() - : propertyDescriptor.getSetter(); - checkFunction(accessor, accessorDescriptor); - checkModifiers(accessor.getModifierList()); - if (propertyDescriptor.getModality() == Modality.FINAL && accessor.hasModifier(JetTokens.OPEN_KEYWORD)) { - ASTNode openModifierNode = accessor.getModifierList().getModifierNode(JetTokens.OPEN_KEYWORD); - context.getTrace().report(NON_FINAL_ACCESSOR_OF_FINAL_PROPERTY.on(accessor, openModifierNode, property)); + checkIllegalInThisContextModifiers(accessor.getModifierList(), Sets.newHashSet(JetTokens.ABSTRACT_KEYWORD, JetTokens.OPEN_KEYWORD, JetTokens.FINAL_KEYWORD, JetTokens.OVERRIDE_KEYWORD)); + } + JetPropertyAccessor getter = property.getGetter(); + PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter(); + JetModifierList getterModifierList = getter != null ? getter.getModifierList() : null; + if (getterModifierList != null && getterDescriptor != null) { + Map nodes = getNodesCorrespondingToModifiers(getterModifierList, Sets.newHashSet(JetTokens.PUBLIC_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.PRIVATE_KEYWORD, JetTokens.INTERNAL_KEYWORD)); + if (getterDescriptor.getVisibility() != propertyDescriptor.getVisibility()) { + for (Map.Entry entry : nodes.entrySet()) { + context.getTrace().report(Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY.on(getterModifierList, entry.getValue(), entry.getKey())); + } } - if (propertyDescriptor.getModality() != Modality.ABSTRACT && accessor.hasModifier(JetTokens.ABSTRACT_KEYWORD)) { - ASTNode abstractModifierNode = accessor.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD); - context.getTrace().report(ABSTRACT_ACCESSOR_OF_NON_ABSTRACT_PROPERTY.on(accessor, abstractModifierNode, property)); + else { + for (Map.Entry entry : nodes.entrySet()) { + context.getTrace().report(Errors.REDUNDANT_MODIFIER_IN_GETTER.on(getterModifierList, entry.getValue(), entry.getKey())); + } } } } @@ -346,12 +358,23 @@ public class DeclarationsChecker { } } - private void checkIllegalInThisContextModifiers(@Nullable JetModifierList modifierList, JetKeywordToken... illegalModifiers) { + private void checkIllegalInThisContextModifiers(@Nullable JetModifierList modifierList, Collection illegalModifiers) { if (modifierList == null) return; for (JetKeywordToken modifier : illegalModifiers) { if (modifierList.hasModifier(modifier)) { - context.getTrace().report(Errors.ILLEGAL_MODIFIER.on(modifierList.getModifierNode(modifier), modifier)); + context.getTrace().report(Errors.ILLEGAL_MODIFIER.on(modifierList, modifierList.getModifierNode(modifier), modifier)); } } } + + @NotNull + public static Map getNodesCorrespondingToModifiers(@NotNull JetModifierList modifierList, Collection possibleModifiers) { + Map nodes = Maps.newHashMap(); + for (JetKeywordToken modifier : possibleModifiers) { + if (modifierList.hasModifier(modifier)) { + nodes.put(modifier, modifierList.getModifierNode(modifier)); + } + } + return nodes; + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java index 42fb64620ed..ba492a83cde 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java @@ -4,11 +4,14 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.*; import java.util.List; import java.util.Map; +import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER; + /** * @author abreslav */ @@ -22,7 +25,7 @@ public class DescriptorUtils { @Override public Boolean visitFunctionDescriptor(FunctionDescriptor descriptor, Void data) { - return descriptor.getReceiver().exists(); + return descriptor.getReceiverParameter().exists(); } @Override @@ -32,7 +35,7 @@ public class DescriptorUtils { @Override public Boolean visitPropertyDescriptor(PropertyDescriptor descriptor, Void data) { - return descriptor.getReceiver().exists(); + return descriptor.getReceiverParameter().exists(); } }, null); } @@ -111,4 +114,13 @@ public class DescriptorUtils { if (makeNonAbstract && modality == Modality.ABSTRACT) return Modality.OPEN; return modality; } + + @NotNull + public static ReceiverDescriptor getExpectedThisObjectIfNeeded(@NotNull DeclarationDescriptor containingDeclaration) { + if (containingDeclaration instanceof ClassDescriptor) { + ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; + return classDescriptor.getImplicitReceiver(); + } + return NO_RECEIVER; + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java index 67e12a470e7..6f52c4737ce 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java @@ -253,7 +253,7 @@ public class OverrideResolver { } if (hasOverrideModifier && declared.getOverriddenDescriptors().size() == 0) { // context.getTrace().getErrorHandler().genericError(overrideNode, "Method " + declared.getName() + " overrides nothing"); - context.getTrace().report(NOTHING_TO_OVERRIDE.on(member, overrideNode, declared)); + context.getTrace().report(NOTHING_TO_OVERRIDE.on(modifierList, overrideNode, declared)); } PsiElement nameIdentifier = member.getNameIdentifier(); if (!hasOverrideModifier && declared.getOverriddenDescriptors().size() > 0 && nameIdentifier != null) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java index 314f847b5ef..bc91949cc9b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java @@ -4,6 +4,7 @@ import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.types.*; @@ -37,24 +38,31 @@ public class OverridingUtil { } public static Set filterOverrides(Set candidateSet) { + return filterOverrides(candidateSet, Function.ID); + } + + public static Set filterOverrides(Set candidateSet, Function transform) { Set candidates = Sets.newLinkedHashSet(); outerLoop: - for (D me : candidateSet) { - for (D other : candidateSet) { + for (D meD : candidateSet) { + CallableDescriptor me = transform.fun(meD); + for (D otherD : candidateSet) { + CallableDescriptor other = transform.fun(otherD); if (me == other) continue; if (overrides(other, me)) { continue outerLoop; } } - for (D other : candidates) { + for (D otherD : candidates) { + CallableDescriptor other = transform.fun(otherD); if (me.getOriginal() == other.getOriginal() - && isOverridableBy(other, me).isSuccess() - && isOverridableBy(me, other).isSuccess()) { + && isOverridableBy(other, me).isSuccess() + && isOverridableBy(me, other).isSuccess()) { continue outerLoop; } } // System.out.println(me); - candidates.add(me); + candidates.add(meD); } // Set candidates = Sets.newLinkedHashSet(candidateSet); // for (D descriptor : candidateSet) { 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..e2789599d2a 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()); @@ -227,18 +227,20 @@ public class TypeHierarchyResolver { } else { ClassifierDescriptor classifierDescriptor = null; + NamespaceDescriptor namespaceDescriptor = null; JetSimpleNameExpression referenceExpression = null; 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; String referencedName = referenceExpression.getReferencedName(); if (type != null && referencedName != null) { classifierDescriptor = type.getMemberScope().getClassifier(referencedName); + namespaceDescriptor = type.getMemberScope().getNamespace(referencedName); } } } @@ -249,15 +251,28 @@ public class TypeHierarchyResolver { String referencedName = referenceExpression.getReferencedName(); if (referencedName != null) { classifierDescriptor = outerScope.getClassifier(referencedName); + namespaceDescriptor = outerScope.getNamespace(referencedName); } } + String aliasName = importDirective.getAliasName(); + if (aliasName == null) { + aliasName = referenceExpression != null ? referenceExpression.getReferencedName() : null; + } if (classifierDescriptor != null) { context.getTrace().record(BindingContext.REFERENCE_TARGET, referenceExpression, classifierDescriptor); - String aliasName = importDirective.getAliasName(); - String importedClassifierName = aliasName != null ? aliasName : classifierDescriptor.getName(); - namespaceScope.importClassifierAlias(importedClassifierName, classifierDescriptor); + if (aliasName != null) { + namespaceScope.importClassifierAlias(aliasName, classifierDescriptor); + } + } + if (namespaceDescriptor != null) { + if (classifierDescriptor == null) { + context.getTrace().record(BindingContext.REFERENCE_TARGET, referenceExpression, namespaceDescriptor); + } + if (aliasName != null) { + namespaceScope.importNamespaceAlias(aliasName, namespaceDescriptor); + } } } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastReceiver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastReceiver.java new file mode 100644 index 00000000000..00c7fde93b7 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastReceiver.java @@ -0,0 +1,35 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.resolve.scopes.receivers.AbstractReceiverDescriptor; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptorVisitor; +import org.jetbrains.jet.lang.types.JetType; + +/** + * @author abreslav + */ +public class AutoCastReceiver extends AbstractReceiverDescriptor { + private final ReceiverDescriptor original; + private final boolean canCast; + + public AutoCastReceiver(@NotNull ReceiverDescriptor original, @NotNull JetType castTo, boolean canCast) { + super(castTo); + this.original = original; + this.canCast = canCast; + } + + public boolean canCast() { + return canCast; + } + + @NotNull + public ReceiverDescriptor getOriginal() { + return original; + } + + @Override + public R accept(@NotNull ReceiverDescriptorVisitor visitor, D data) { + return original.accept(visitor, data); + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastService.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastService.java new file mode 100644 index 00000000000..f5b928cda82 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastService.java @@ -0,0 +1,35 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.types.DataFlowInfo; + +import java.util.Collections; +import java.util.List; + +/** +* @author abreslav +*/ +public interface AutoCastService { + AutoCastService NO_AUTO_CASTS = new AutoCastService() { + @Override + public DataFlowInfo getDataFlowInfo() { + return DataFlowInfo.getEmpty(); + } + + @Override + public boolean isNotNull(@NotNull ReceiverDescriptor receiver) { + return !receiver.getType().isNullable(); + } + + @Override + public List getVariantsForReceiver(ReceiverDescriptor receiverDescriptor) { + return Collections.singletonList(receiverDescriptor); + } + }; + + List getVariantsForReceiver(ReceiverDescriptor receiverDescriptor); + DataFlowInfo getDataFlowInfo(); + + boolean isNotNull(@NotNull ReceiverDescriptor receiver); +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastServiceImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastServiceImpl.java new file mode 100644 index 00000000000..2cf6f33dbfe --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastServiceImpl.java @@ -0,0 +1,42 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.types.DataFlowInfo; + +import java.util.List; + +/** +* @author abreslav +*/ +public class AutoCastServiceImpl implements AutoCastService { + private final DataFlowInfo dataFlowInfo; + private final BindingContext bindingContext; + + public AutoCastServiceImpl(DataFlowInfo dataFlowInfo, BindingContext bindingContext) { + this.dataFlowInfo = dataFlowInfo; + this.bindingContext = bindingContext; + } + + @Override + public List getVariantsForReceiver(ReceiverDescriptor receiverDescriptor) { + return AutoCastUtils.getAutoCastVariants(bindingContext, dataFlowInfo, receiverDescriptor); + } + + @Override + public DataFlowInfo getDataFlowInfo() { + return dataFlowInfo; + } + + @Override + public boolean isNotNull(@NotNull ReceiverDescriptor receiver) { + if (!receiver.getType().isNullable()) return true; + + List autoCastVariants = AutoCastUtils.getAutoCastVariants(bindingContext, dataFlowInfo, receiver); + for (ReceiverDescriptor autoCastVariant : autoCastVariants) { + if (!autoCastVariant.getType().isNullable()) return true; + } + return false; + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastUtils.java new file mode 100644 index 00000000000..26e8588e666 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastUtils.java @@ -0,0 +1,149 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import com.google.common.collect.Lists; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.JetPsiUtil; +import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; +import org.jetbrains.jet.lang.psi.JetThisExpression; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.BindingTrace; +import org.jetbrains.jet.lang.resolve.scopes.receivers.*; +import org.jetbrains.jet.lang.types.DataFlowInfo; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.JetTypeChecker; + +import java.util.Collections; +import java.util.List; + +import static org.jetbrains.jet.lang.diagnostics.Errors.AUTOCAST_IMPOSSIBLE; +import static org.jetbrains.jet.lang.resolve.BindingContext.AUTOCAST; +import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; + +/** + * @author abreslav + */ +public class AutoCastUtils { + + private AutoCastUtils() {} + + public static List getAutoCastVariants(@NotNull final BindingContext bindingContext, @NotNull final DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiverToCast) { + return receiverToCast.accept(new ReceiverDescriptorVisitor, Object>() { + @Override + public List visitNoReceiver(ReceiverDescriptor noReceiver, Object data) { + return Collections.emptyList(); + } + + @Override + public List visitTransientReceiver(TransientReceiver receiver, Object data) { + return Collections.emptyList(); + } + + @Override + public List visitExtensionReceiver(ExtensionReceiver receiver, Object data) { + return castThis(dataFlowInfo, receiver); + } + + @Override + public List visitClassReceiver(ClassReceiver receiver, Object data) { + return castThis(dataFlowInfo, receiver); + } + + @Override + public List visitExpressionReceiver(ExpressionReceiver receiver, Object data) { + JetExpression expression = receiver.getExpression(); + VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(bindingContext, expression); + if (variableDescriptor != null) { + List result = Lists.newArrayList(); + for (JetType possibleType : dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)) { + result.add(new AutoCastReceiver(receiver, possibleType, isAutoCastable(variableDescriptor))); + } + return result; + } + else if (expression instanceof JetThisExpression) { + return castThis(dataFlowInfo, receiver); + } + return Collections.emptyList(); + } + }, null); + } + + private static List castThis(@NotNull DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiver) { + assert receiver.exists(); + List result = Lists.newArrayList(); + for (JetType possibleType : dataFlowInfo.getPossibleTypesForReceiver(receiver)) { + result.add(new AutoCastReceiver(receiver, possibleType, true)); + } + return result; + } + + @Nullable + public static JetType castExpression(@NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) { + JetTypeChecker typeChecker = JetTypeChecker.INSTANCE; + VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(trace.getBindingContext(), expression); +// boolean appropriateTypeFound = false; + if (variableDescriptor != null) { + List possibleTypes = Lists.newArrayList(dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)); + Collections.reverse(possibleTypes); + for (JetType possibleType : possibleTypes) { + if (typeChecker.isSubtypeOf(possibleType, expectedType)) { + if (isAutoCastable(variableDescriptor)) { + trace.record(AUTOCAST, expression, possibleType); + } + else { + trace.report(AUTOCAST_IMPOSSIBLE.on(expression, possibleType, expression.getText())); + } + return possibleType; + } + } +// if (!appropriateTypeFound) { +// JetType notnullType = dataFlowInfo.getOutType(variableDescriptor); +// if (notnullType != null && typeChecker.isSubtypeOf(notnullType, expectedType)) { +// appropriateTypeFound = true; +// } +// } + } + return null; + } + + @Nullable + public static VariableDescriptor getVariableDescriptorFromSimpleName(@NotNull BindingContext bindingContext, @NotNull JetExpression expression) { +// if (expression instanceof JetBinaryExpressionWithTypeRHS) { +// JetBinaryExpressionWithTypeRHS expression = (JetBinaryExpressionWithTypeRHS) expression; +// if (expression.getOperationSign().getReferencedNameElementType() == JetTokens.COLON) { +// return getVariableDescriptorFromSimpleName(bindingContext, expression.getLeft()); +// } +// } + JetExpression receiver = JetPsiUtil.deparenthesize(expression); + VariableDescriptor variableDescriptor = null; + if (receiver instanceof JetSimpleNameExpression) { + JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) receiver; + DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, nameExpression); + if (declarationDescriptor instanceof VariableDescriptor) { + variableDescriptor = (VariableDescriptor) declarationDescriptor; + } + } + return variableDescriptor; + } + + public static boolean isAutoCastable(@NotNull VariableDescriptor variableDescriptor) { + if (variableDescriptor.isVar()) return false; + if (variableDescriptor instanceof PropertyDescriptor) { + PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor; + DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); + if (containingDeclaration instanceof ClassDescriptor) { + ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; + if (classDescriptor.getModality().isOverridable() && propertyDescriptor.getModality().isOverridable()) return false; + } + else { + assert !propertyDescriptor.getModality().isOverridable() : "Property outside a class must not be overridable"; + } + PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); + if (getter == null || !getter.isDefault()) return false; + } + return true; + } + +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index d37dfa72ee0..d0f8b0ee111 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -1,11 +1,10 @@ package org.jetbrains.jet.lang.resolve.calls; -import com.google.common.base.Function; -import com.google.common.base.Functions; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.JetSemanticServices; @@ -13,16 +12,19 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.inference.ConstraintSystem; +import org.jetbrains.jet.lexer.JetTokens; import java.util.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*; -import static org.jetbrains.jet.lang.resolve.BindingContext.AMBIGUOUS_REFERENCE_TARGET; -import static org.jetbrains.jet.lang.resolve.BindingContext.RECEIVER; -import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; +import static org.jetbrains.jet.lang.resolve.BindingContext.*; +import static org.jetbrains.jet.lang.resolve.calls.ResolutionStatus.*; +import static org.jetbrains.jet.lang.resolve.calls.ResolvedCall.MAP_TO_CANDIDATE; +import static org.jetbrains.jet.lang.resolve.calls.ResolvedCall.MAP_TO_RESULT; import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER; import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE; @@ -34,39 +36,43 @@ public class CallResolver { private final JetTypeInferrer typeInferrer; private final JetSemanticServices semanticServices; private final OverloadingConflictResolver overloadingConflictResolver; + private final DataFlowInfo dataFlowInfo; - public CallResolver(JetSemanticServices semanticServices, JetTypeInferrer typeInferrer) { + public CallResolver(JetSemanticServices semanticServices, JetTypeInferrer typeInferrer, DataFlowInfo dataFlowInfo) { this.typeInferrer = typeInferrer; this.semanticServices = semanticServices; this.overloadingConflictResolver = new OverloadingConflictResolver(semanticServices); + this.dataFlowInfo = dataFlowInfo; } @Nullable public VariableDescriptor resolveSimpleProperty( @NotNull BindingTrace trace, @NotNull JetScope scope, - @NotNull ReceiverDescriptor receiver, - @NotNull final JetSimpleNameExpression nameExpression, +// @NotNull ReceiverDescriptor receiver, +// @NotNull final JetSimpleNameExpression nameExpression, + @NotNull Call call, @NotNull JetType expectedType) { +// Call call = CallMaker.makePropertyCall(receiver, null, nameExpression); + JetExpression calleeExpression = call.getCalleeExpression(); + assert calleeExpression instanceof JetSimpleNameExpression; + JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) calleeExpression; String referencedName = nameExpression.getReferencedName(); if (referencedName == null) { return null; } - Call call = CallMaker.makePropertyCall(nameExpression); - List> prioritizedTasks = PROPERTY_TASK_PRIORITIZER.computePrioritizedTasks(scope, receiver, call, referencedName); - return resolveCallToDescriptor(trace, scope, call, nameExpression.getNode(), expectedType, prioritizedTasks, nameExpression); + List> prioritizedTasks = TaskPrioritizers.PROPERTY_TASK_PRIORITIZER.computePrioritizedTasks(scope, call, referencedName, trace.getBindingContext(), dataFlowInfo); + return resolveCallToDescriptor(trace, scope, call, expectedType, prioritizedTasks, nameExpression); } - @Nullable public JetType resolveCall( @NotNull BindingTrace trace, @NotNull JetScope scope, - @NotNull ReceiverDescriptor receiver, - @NotNull JetCallElement call, + @NotNull Call call, @NotNull JetType expectedType ) { - FunctionDescriptor functionDescriptor = resolveSimpleCallToFunctionDescriptor(trace, scope, receiver, call, expectedType); + FunctionDescriptor functionDescriptor = resolveSimpleCallToFunctionDescriptor(trace, scope, call, expectedType); return functionDescriptor == null ? null : functionDescriptor.getReturnType(); } @@ -77,20 +83,16 @@ public class CallResolver { @NotNull final Call call, @NotNull final JetReferenceExpression functionReference, @NotNull String name, - @NotNull ReceiverDescriptor receiver, @NotNull JetType expectedType) { - // TODO : autocasts - // TODO : nullability - List> tasks = FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, receiver, call, name); - return resolveCallToDescriptor(trace, scope, call, functionReference.getNode(), expectedType, tasks, functionReference); + List> tasks = TaskPrioritizers.FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, call, name, trace.getBindingContext(), dataFlowInfo); + return resolveCallToDescriptor(trace, scope, call, expectedType, tasks, functionReference); } @Nullable public FunctionDescriptor resolveSimpleCallToFunctionDescriptor( @NotNull BindingTrace trace, @NotNull JetScope scope, - @NotNull ReceiverDescriptor receiver, - @NotNull final JetCallElement call, + @NotNull final Call call, @NotNull JetType expectedType ) { List> prioritizedTasks; @@ -104,7 +106,7 @@ public class CallResolver { String name = expression.getReferencedName(); if (name == null) return checkArgumentTypesAndFail(trace, scope, call); - prioritizedTasks = FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, receiver, call, name); + prioritizedTasks = TaskPrioritizers.FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, call, name, trace.getBindingContext(), dataFlowInfo); ResolutionTask.DescriptorCheckStrategy abstractConstructorCheck = new ResolutionTask.DescriptorCheckStrategy() { @Override public boolean performAdvancedChecks(D descriptor, BindingTrace trace, TracingStrategy tracing) { @@ -125,9 +127,9 @@ public class CallResolver { } else { JetValueArgumentList valueArgumentList = call.getValueArgumentList(); - ASTNode reportAbsenceOn = valueArgumentList == null ? call.getNode() : valueArgumentList.getNode(); + ASTNode reportAbsenceOn = valueArgumentList == null ? call.getCallNode() : valueArgumentList.getNode(); if (calleeExpression instanceof JetConstructorCalleeExpression) { - assert receiver == NO_RECEIVER; + assert !call.getExplicitReceiver().exists(); prioritizedTasks = Lists.newArrayList(); @@ -148,7 +150,7 @@ public class CallResolver { trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn)); return checkArgumentTypesAndFail(trace, scope, call); } - prioritizedTasks.add(new ResolutionTask(constructors, NO_RECEIVER, call)); + prioritizedTasks.add(new ResolutionTask(TaskPrioritizer.convertWithImpliedThis(scope, Collections.singletonList(NO_RECEIVER), constructors), call, DataFlowInfo.getEmpty())); } else { // trace.getErrorHandler().genericError(calleeExpression.getNode(), "Not a class"); @@ -162,48 +164,65 @@ public class CallResolver { assert containingDeclaration instanceof ClassDescriptor; ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; - Set constructors = classDescriptor.getConstructors(); if (constructors.isEmpty()) { // trace.getErrorHandler().genericError(reportAbsenceOn, "This class does not have a constructor"); trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn)); return checkArgumentTypesAndFail(trace, scope, call); } - prioritizedTasks = Collections.singletonList(new ResolutionTask(constructors, NO_RECEIVER, call)); + prioritizedTasks = Collections.singletonList(new ResolutionTask(ResolvedCall.convertCollection(constructors), call, DataFlowInfo.getEmpty())); } else { - throw new UnsupportedOperationException("Type argument inference not implemented for " + call.getText()); + throw new UnsupportedOperationException("Type argument inference not implemented for " + call); } } - return resolveCallToDescriptor(trace, scope, call, call.getNode(), expectedType, prioritizedTasks, functionReference); + return resolveCallToDescriptor(trace, scope, call, expectedType, prioritizedTasks, functionReference); } - private FunctionDescriptor checkArgumentTypesAndFail(BindingTrace trace, JetScope scope, JetCallElement call) { - checkTypesWithNoCallee(trace, scope, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments()); + private FunctionDescriptor checkArgumentTypesAndFail(BindingTrace trace, JetScope scope, Call call) { + checkTypesWithNoCallee(trace, scope, call); return null; } - + @Nullable private D resolveCallToDescriptor( @NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull final Call call, - @NotNull final ASTNode callNode, + @NotNull JetType expectedType, + @NotNull final List> prioritizedTasks, // high to low priority + @NotNull final JetReferenceExpression reference) { + ResolvedCall resolvedCall = doResolveCall(trace, scope, call, expectedType, prioritizedTasks, reference); + return resolvedCall == null ? null : resolvedCall.getResultingDescriptor(); + } + + @Nullable + private ResolvedCall doResolveCall( + @NotNull BindingTrace trace, + @NotNull JetScope scope, + @NotNull final Call call, @NotNull JetType expectedType, @NotNull final List> prioritizedTasks, // high to low priority @NotNull final JetReferenceExpression reference) { TemporaryBindingTrace traceForFirstNonemptyCandidateSet = null; - OverloadResolutionResult resultForFirstNonemptyCandidateSet = null; + OverloadResolutionResults resultsForFirstNonemptyCandidateSet = null; TracingStrategy tracing = new TracingStrategy() { @Override - public void bindReference(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor receiver, @NotNull CallableDescriptor descriptor) { - trace.record(REFERENCE_TARGET, reference, descriptor); - trace.record(RECEIVER, reference, receiver); + public void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCall resolvedCall) { + D descriptor = resolvedCall.getCandidateDescriptor(); +// if (descriptor instanceof VariableAsFunctionDescriptor) { +// VariableAsFunctionDescriptor variableAsFunctionDescriptor = (VariableAsFunctionDescriptor) descriptor; +// trace.record(REFERENCE_TARGET, reference, variableAsFunctionDescriptor.getVariableDescriptor()); +// } +// else { + trace.record(REFERENCE_TARGET, reference, descriptor); +// } + trace.record(RESOLVED_CALL, reference, resolvedCall); } @Override - public void recordAmbiguity(BindingTrace trace, Collection candidates) { + public void recordAmbiguity(BindingTrace trace, Collection> candidates) { trace.record(AMBIGUOUS_REFERENCE_TARGET, reference, candidates); } @@ -214,19 +233,6 @@ public class CallResolver { @Override public void noValueForParameter(@NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter) { -// ASTNode node; -// -// JetValueArgumentList valueArgumentList = call.getValueArgumentList(); -// if (valueArgumentList != null) { -// node = valueArgumentList.getNode(); -// } -// else if (!call.getFunctionLiteralArguments().isEmpty()) { -// node = call.getFunctionLiteralArguments().get(0).getNode(); -// } -// else { -// node = callNode; -// } -// trace.report(NO_VALUE_FOR_PARAMETER.on(node, valueParameter)); trace.report(NO_VALUE_FOR_PARAMETER.on(reference, valueParameter)); } @@ -235,6 +241,17 @@ public class CallResolver { trace.report(MISSING_RECEIVER.on(reference, expectedReceiver.getType())); } + @Override + public void wrongReceiverType(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor receiverParameter, @NotNull ReceiverDescriptor receiverArgument) { + if (receiverArgument instanceof ExpressionReceiver) { + ExpressionReceiver expressionReceiver = (ExpressionReceiver) receiverArgument; + trace.report(TYPE_MISMATCH.on(expressionReceiver.getExpression(), receiverParameter.getType(), receiverArgument.getType())); + } + else { + trace.report(TYPE_MISMATCH.on(reference, receiverParameter.getType(), receiverArgument.getType())); + } + } + @Override public void noReceiverAllowed(@NotNull BindingTrace trace) { trace.report(NO_RECEIVER_ADMITTED.on(reference)); @@ -254,47 +271,75 @@ public class CallResolver { } @Override - public void ambiguity(@NotNull BindingTrace trace, @NotNull Set descriptors) { - trace.report(OVERLOAD_RESOLUTION_AMBIGUITY.on(callNode, descriptors)); + public void ambiguity(@NotNull BindingTrace trace, @NotNull Set> descriptors) { + trace.report(OVERLOAD_RESOLUTION_AMBIGUITY.on(call.getCallNode(), descriptors)); } @Override - public void noneApplicable(@NotNull BindingTrace trace, @NotNull Set descriptors) { - trace.report(NONE_APPLICABLE.on(callNode, descriptors)); + public void noneApplicable(@NotNull BindingTrace trace, @NotNull Set> descriptors) { + trace.report(NONE_APPLICABLE.on(reference, descriptors)); } @Override public void instantiationOfAbstractClass(@NotNull BindingTrace trace) { - trace.report(CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS.on(callNode)); + trace.report(CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS.on(call.getCallNode())); } @Override public void typeInferenceFailed(@NotNull BindingTrace trace) { - trace.report(TYPE_INFERENCE_FAILED.on(callNode)); + trace.report(TYPE_INFERENCE_FAILED.on(call.getCallNode())); } + @Override + public void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type) { + ASTNode callOperationNode = call.getCallOperationNode(); + if (callOperationNode != null) { + trace.report(UNSAFE_CALL.on(callOperationNode, type)); + } + else { + PsiElement callElement = call.getCallElement(); + if (callElement instanceof JetBinaryExpression) { + JetBinaryExpression binaryExpression = (JetBinaryExpression) callElement; + JetSimpleNameExpression operationReference = binaryExpression.getOperationReference(); + String operationString = operationReference.getReferencedNameElementType() == JetTokens.IDENTIFIER ? operationReference.getText() : JetTypeInferrer.getNameForOperationSymbol(operationReference.getReferencedNameElementType()); + trace.report(UNSAFE_INFIX_CALL.on(reference, binaryExpression.getLeft().getText(), operationString, binaryExpression.getRight().getText())); + } + else { + trace.report(UNSAFE_CALL.on(reference, type)); + } + } + } + + @Override + public void unnecessarySafeCall(@NotNull BindingTrace trace, @NotNull JetType type) { + ASTNode callOperationNode = call.getCallOperationNode(); + assert callOperationNode != null; + PsiElement callElement = call.getCallElement(); + assert callElement != null; + trace.report(UNNECESSARY_SAFE_CALL.on((JetElement) callOperationNode.getTreeParent().getPsi(), callOperationNode, type)); + } }; for (ResolutionTask task : prioritizedTasks) { TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(trace); - OverloadResolutionResult result = performResolution(temporaryTrace, scope, expectedType, task, tracing); - if (result.isSuccess()) { + OverloadResolutionResults results = performResolution(temporaryTrace, scope, expectedType, task, tracing); + if (results.isSuccess()) { temporaryTrace.commit(); - return result.getDescriptor(); + return results.getResult(); } if (traceForFirstNonemptyCandidateSet == null && !task.getCandidates().isEmpty()) { traceForFirstNonemptyCandidateSet = temporaryTrace; - resultForFirstNonemptyCandidateSet = result; + resultsForFirstNonemptyCandidateSet = results; } } if (traceForFirstNonemptyCandidateSet != null) { traceForFirstNonemptyCandidateSet.commit(); - if (resultForFirstNonemptyCandidateSet.singleDescriptor()) { - return resultForFirstNonemptyCandidateSet.getDescriptor(); + if (resultsForFirstNonemptyCandidateSet.singleDescriptor()) { + return resultsForFirstNonemptyCandidateSet.getResult(); } } else { trace.report(UNRESOLVED_REFERENCE.on(reference)); - checkTypesWithNoCallee(trace, scope, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments()); + checkTypesWithNoCallee(trace, scope, call); } return null; } @@ -302,48 +347,30 @@ public class CallResolver { ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @NotNull - private OverloadResolutionResult performResolution(@NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull JetType expectedType, @NotNull ResolutionTask task, @NotNull TracingStrategy tracing) { - Map successfulCandidates = Maps.newLinkedHashMap(); - Set failedCandidates = Sets.newLinkedHashSet(); - Set dirtyCandidates = Sets.newLinkedHashSet(); - Map solutions = Maps.newHashMap(); - Map traces = Maps.newHashMap(); - - for (D candidate : task.getCandidates()) { + private OverloadResolutionResults performResolution(@NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull JetType expectedType, @NotNull ResolutionTask task, @NotNull TracingStrategy tracing) { + for (ResolvedCall candidateCall : task.getCandidates()) { + D candidate = candidateCall.getCandidateDescriptor(); TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(trace); - traces.put(candidate, temporaryTrace); - JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace); + candidateCall.setTrace(temporaryTrace); - tracing.bindReference(temporaryTrace, task.getReceiver(), candidate); + tracing.bindReference(temporaryTrace, candidateCall); if (ErrorUtils.isError(candidate)) { - successfulCandidates.put(candidate, candidate); - checkTypesWithNoCallee(temporaryTrace, scope, task.getTypeArguments(), task.getValueArguments(), task.getFunctionLiteralArguments()); + candidateCall.setStatus(SUCCESS); + checkTypesWithNoCallee(temporaryTrace, scope, task.getCall()); continue; } - Flag dirty = new Flag(false); - - Map argumentsToParameters = Maps.newHashMap(); - boolean error = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(task, tracing, candidate, temporaryTrace, argumentsToParameters); - - if (error) { - failedCandidates.add(candidate); - checkTypesWithNoCallee(temporaryTrace, scope, task.getTypeArguments(), task.getValueArguments(), task.getFunctionLiteralArguments()); + boolean errorInArgumentMapping = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(task, tracing, candidateCall); + if (errorInArgumentMapping) { + candidateCall.setStatus(OTHER_ERROR); + checkTypesWithNoCallee(temporaryTrace, scope, task.getCall()); continue; } - if (task.getTypeArguments().isEmpty()) { - if (candidate.getTypeParameters().isEmpty()) { - if (checkValueArgumentTypes(scope, temporaryServices, argumentsToParameters, dirty, Functions.identity()) - && checkReceiver(task, tracing, candidate, temporaryTrace)) { - successfulCandidates.put(candidate, candidate); - } - else { - failedCandidates.add(candidate); - } - } - else { + List jetTypeArguments = task.getCall().getTypeArguments(); + if (jetTypeArguments.isEmpty()) { + if (!candidate.getTypeParameters().isEmpty()) { // Type argument inference ConstraintSystem constraintSystem = new ConstraintSystem(); @@ -351,27 +378,31 @@ public class CallResolver { constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO } - for (Map.Entry entry : argumentsToParameters.entrySet()) { - ValueArgument valueArgument = entry.getKey(); - ValueParameterDescriptor valueParameterDescriptor = entry.getValue(); + for (Map.Entry entry : candidateCall.getValueArguments().entrySet()) { + ResolvedValueArgument valueArgument = entry.getValue(); + ValueParameterDescriptor valueParameterDescriptor = entry.getKey(); - JetExpression expression = valueArgument.getArgumentExpression(); - // TODO : more attempts, with different expected types - JetType type = temporaryServices.getType(scope, expression, NO_EXPECTED_TYPE); - if (type != null) { - constraintSystem.addSubtypingConstraint(type, valueParameterDescriptor.getOutType()); - } - else { - dirty.setValue(true); + for (JetExpression expression : valueArgument.getArgumentExpressions()) { +// JetExpression expression = valueArgument.getArgumentExpression(); + // TODO : more attempts, with different expected types + JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace); + JetType type = temporaryServices.getType(scope, expression, NO_EXPECTED_TYPE); + if (type != null) { + constraintSystem.addSubtypingConstraint(type, valueParameterDescriptor.getOutType()); + } + else { + candidateCall.argumentHasNoType(); + } } } - checkReceiverAbsence(task, tracing, candidate, temporaryTrace); +// checkReceiverAbsence(candidateCall, tracing, candidate); + // Error is already reported if something is missing - ReceiverDescriptor receiver = task.getReceiver(); - ReceiverDescriptor candidateReceiver = candidate.getReceiver(); - if (receiver != NO_RECEIVER && candidateReceiver != NO_RECEIVER) { - constraintSystem.addSubtypingConstraint(receiver.getType(), candidateReceiver.getType()); + ReceiverDescriptor receiverParameter = candidateCall.getReceiverArgument(); + ReceiverDescriptor candidateReceiver = candidate.getReceiverParameter(); + if (receiverParameter.exists() && candidateReceiver.exists()) { + constraintSystem.addSubtypingConstraint(receiverParameter.getType(), candidateReceiver.getType()); } if (expectedType != NO_EXPECTED_TYPE) { @@ -379,23 +410,26 @@ public class CallResolver { } ConstraintSystem.Solution solution = constraintSystem.solve(); - solutions.put(candidate, solution); +// solutions.put(candidate, solution); if (solution.isSuccessful()) { D substitute = (D) candidate.substitute(solution.getSubstitutor()); assert substitute != null; - successfulCandidates.put(candidate, substitute); + replaceValueParametersWithSubstitutedOnes(candidateCall, substitute); + candidateCall.setResultingDescriptor(substitute); + candidateCall.setStatus(SUCCESS); } else { tracing.typeInferenceFailed(temporaryTrace); - failedCandidates.add(candidate); + candidateCall.setStatus(OTHER_ERROR); } } + else { + candidateCall.setStatus(checkAllValueArguments(scope, tracing, task, candidateCall)); + } } else { // Explicit type arguments passed - final List jetTypeArguments = task.getTypeArguments(); - for (JetTypeProjection typeArgument : jetTypeArguments) { if (typeArgument.getProjectionKind() != JetProjectionKind.NONE) { // temporaryTrace.getErrorHandler().genericError(typeArgument.getNode(), "Projections are not allowed on type parameters for methods"); // TODO : better positioning @@ -415,187 +449,282 @@ public class CallResolver { } checkGenericBoundsInAFunctionCall(jetTypeArguments, typeArguments, candidate, temporaryTrace); - + Map substitutionContext = FunctionDescriptorUtil.createSubstitutionContext((FunctionDescriptor) candidate, typeArguments); - D substitutedFunctionDescriptor = (D) candidate.substitute(TypeSubstitutor.create(substitutionContext)); + D substitutedDescriptor = (D) candidate.substitute(TypeSubstitutor.create(substitutionContext)); - Function mapFunction = createMapFunction(substitutedFunctionDescriptor); - if (checkValueArgumentTypes(scope, temporaryServices, argumentsToParameters, dirty, mapFunction) - && checkReceiver(task, tracing, substitutedFunctionDescriptor, temporaryTrace)) { - successfulCandidates.put(candidate, substitutedFunctionDescriptor); - } - else { - failedCandidates.add(candidate); - } + candidateCall.setResultingDescriptor(substitutedDescriptor); + replaceValueParametersWithSubstitutedOnes(candidateCall, substitutedDescriptor); + candidateCall.setStatus(checkAllValueArguments(scope, tracing, task, candidateCall)); } else { - failedCandidates.add(candidate); + candidateCall.setStatus(OTHER_ERROR); // tracing.reportWrongTypeArguments(temporaryTrace, "Number of type arguments does not match " + DescriptorRenderer.TEXT.render(candidate)); tracing.wrongNumberOfTypeArguments(temporaryTrace, expectedTypeArgumentCount); } } - if (dirty.getValue()) { - dirtyCandidates.add(candidate); - } task.performAdvancedChecks(candidate, temporaryTrace, tracing); + + recordAutoCastIfNecessary(candidateCall.getReceiverArgument(), candidateCall.getTrace()); + recordAutoCastIfNecessary(candidateCall.getThisObject(), candidateCall.getTrace()); } - OverloadResolutionResult result = computeResultAndReportErrors(trace, tracing, successfulCandidates, failedCandidates, dirtyCandidates, traces); - if (!result.singleDescriptor()) { - checkTypesWithNoCallee(trace, scope, task.getTypeArguments(), task.getValueArguments(), task.getFunctionLiteralArguments()); + Set> successfulCandidates = Sets.newLinkedHashSet(); + Set> failedCandidates = Sets.newLinkedHashSet(); + for (ResolvedCall candidateCall : task.getCandidates()) { + ResolutionStatus status = candidateCall.getStatus(); + if (status.isSuccess()) { + successfulCandidates.add(candidateCall); + } + else { + assert status != UNKNOWN_STATUS : "No resolution for " + candidateCall.getCandidateDescriptor(); + failedCandidates.add(candidateCall); + } } - return result; + + OverloadResolutionResults results = computeResultAndReportErrors(trace, tracing, successfulCandidates, failedCandidates); + if (!results.singleDescriptor()) { + checkTypesWithNoCallee(trace, scope, task.getCall()); + } + return results; } - private void checkTypesWithNoCallee(BindingTrace trace, JetScope scope, List typeArguments, List valueArguments, List functionLiteralArguments) { - for (ValueArgument valueArgument : valueArguments) { + private void recordAutoCastIfNecessary(ReceiverDescriptor receiver, BindingTrace trace) { + if (receiver instanceof AutoCastReceiver) { + AutoCastReceiver autoCastReceiver = (AutoCastReceiver) receiver; + ReceiverDescriptor original = autoCastReceiver.getOriginal(); + if (original instanceof ExpressionReceiver) { + ExpressionReceiver expressionReceiver = (ExpressionReceiver) original; + if (autoCastReceiver.canCast()) { + trace.record(AUTOCAST, expressionReceiver.getExpression(), autoCastReceiver.getType()); + } + else { + trace.report(AUTOCAST_IMPOSSIBLE.on(expressionReceiver.getExpression(), autoCastReceiver.getType(), expressionReceiver.getExpression().getText())); + } + } + else { + assert autoCastReceiver.canCast() : "A non-expression receiver must always be autocastabe: " + original; + } + } + } + + private void checkTypesWithNoCallee(BindingTrace trace, JetScope scope, Call call) { + for (ValueArgument valueArgument : call.getValueArguments()) { JetExpression argumentExpression = valueArgument.getArgumentExpression(); if (argumentExpression != null) { typeInferrer.getServices(trace).getType(scope, argumentExpression, NO_EXPECTED_TYPE); } } - for (JetExpression expression : functionLiteralArguments) { + for (JetExpression expression : call.getFunctionLiteralArguments()) { typeInferrer.getServices(trace).getType(scope, expression, NO_EXPECTED_TYPE); } - for (JetTypeProjection typeProjection : typeArguments) { + for (JetTypeProjection typeProjection : call.getTypeArguments()) { new TypeResolver(semanticServices, trace, true).resolveType(scope, typeProjection.getTypeReference()); } } - private Function createMapFunction(D substitutedFunctionDescriptor) { - assert substitutedFunctionDescriptor != null; - final Map parameterMap = Maps.newHashMap(); - for (ValueParameterDescriptor valueParameterDescriptor : substitutedFunctionDescriptor.getValueParameters()) { +// private Function createMapFunction(D substitutedFunctionDescriptor) { +// assert substitutedFunctionDescriptor != null; +// final Map parameterMap = Maps.newHashMap(); +// for (ValueParameterDescriptor valueParameterDescriptor : substitutedFunctionDescriptor.getValueParameters()) { +// parameterMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor); +// } +// +// return new Function() { +// @Override +// public ValueParameterDescriptor apply(ValueParameterDescriptor input) { +// return parameterMap.get(input.getOriginal()); +// } +// }; +// } + + private void replaceValueParametersWithSubstitutedOnes(ResolvedCall candidateCall, @NotNull D substitutedDescriptor) { + Map parameterMap = Maps.newHashMap(); + for (ValueParameterDescriptor valueParameterDescriptor : substitutedDescriptor.getValueParameters()) { parameterMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor); } - return new Function() { - @Override - public ValueParameterDescriptor apply(ValueParameterDescriptor input) { - return parameterMap.get(input.getOriginal()); - } - }; + Map valueArguments = candidateCall.getValueArguments(); + Map originalValueArguments = Maps.newHashMap(valueArguments); + valueArguments.clear(); + for (Map.Entry entry : originalValueArguments.entrySet()) { + ValueParameterDescriptor substitutedVersion = parameterMap.get(entry.getKey().getOriginal()); + assert substitutedVersion != null : entry.getKey(); + valueArguments.put(substitutedVersion, entry.getValue()); + } } - private boolean checkReceiver(ResolutionTask task, TracingStrategy tracing, D candidate, TemporaryBindingTrace temporaryTrace) { - if (!checkReceiverAbsence(task, tracing, candidate, temporaryTrace)) return false; - ReceiverDescriptor receiver = task.getReceiver(); - ReceiverDescriptor candidateReceiver = candidate.getReceiver(); - if (receiver != NO_RECEIVER - && candidateReceiver != NO_RECEIVER - && !semanticServices.getTypeChecker().isSubtypeOf(receiver.getType(), candidateReceiver.getType())) { - tracing.missingReceiver(temporaryTrace, candidateReceiver); - return false; - } - return true; + private ResolutionStatus checkAllValueArguments(JetScope scope, TracingStrategy tracing, ResolutionTask task, ResolvedCall candidateCall) { + ResolutionStatus result = checkValueArgumentTypes(scope, candidateCall); + result = result.combine(checkReceiver(tracing, candidateCall, candidateCall.getResultingDescriptor().getReceiverParameter(), candidateCall.getReceiverArgument(), task)); + result = result.combine(checkReceiver(tracing, candidateCall, candidateCall.getResultingDescriptor().getExpectedThisObject(), candidateCall.getThisObject(), task)); + return result; } - private boolean checkReceiverAbsence(ResolutionTask task, TracingStrategy tracing, D candidate, TemporaryBindingTrace temporaryTrace) { - ReceiverDescriptor receiver = task.getReceiver(); - ReceiverDescriptor candidateReceiver = candidate.getReceiver(); - if (receiver != NO_RECEIVER) { - if (candidateReceiver == NO_RECEIVER) { - tracing.noReceiverAllowed(temporaryTrace); - return false; + private ResolutionStatus checkReceiver(TracingStrategy tracing, ResolvedCall candidateCall, ReceiverDescriptor receiverParameter, ReceiverDescriptor receiverArgument, ResolutionTask task) { + ResolutionStatus result = SUCCESS; + if (receiverParameter.exists() && receiverArgument.exists()) { + ASTNode callOperationNode = task.getCall().getCallOperationNode(); + boolean safeAccess = callOperationNode != null && callOperationNode.getElementType() == JetTokens.SAFE_ACCESS; + JetType receiverArgumentType = receiverArgument.getType(); + AutoCastServiceImpl autoCastService = new AutoCastServiceImpl(task.getDataFlowInfo(), candidateCall.getTrace().getBindingContext()); + if (!safeAccess && !receiverParameter.getType().isNullable() && !autoCastService.isNotNull(receiverArgument)) { + tracing.unsafeCall(candidateCall.getTrace(), receiverArgumentType); + result = UNSAFE_CALL_ERROR; + } + else { + JetType effectiveReceiverArgumentType = safeAccess + ? TypeUtils.makeNotNullable(receiverArgumentType) + : receiverArgumentType; + if (!semanticServices.getTypeChecker().isSubtypeOf(effectiveReceiverArgumentType, receiverParameter.getType())) { + tracing.wrongReceiverType(candidateCall.getTrace(), receiverParameter, receiverArgument); + result = OTHER_ERROR; + } + } + + if (safeAccess && (receiverParameter.getType().isNullable() || !receiverArgumentType.isNullable())) { + tracing.unnecessarySafeCall(candidateCall.getTrace(), receiverArgumentType); } } - else if (candidateReceiver != NO_RECEIVER) { - tracing.missingReceiver(temporaryTrace, candidateReceiver); - return false; + return result; + } + + private ResolutionStatus checkValueArgumentTypes(JetScope scope, ResolvedCall candidateCall) { + ResolutionStatus result = SUCCESS; + for (Map.Entry entry : candidateCall.getValueArguments().entrySet()) { + ValueParameterDescriptor parameterDescriptor = entry.getKey(); + ResolvedValueArgument resolvedArgument = entry.getValue(); + + JetType parameterType = parameterDescriptor.getOutType(); + + List argumentExpressions = resolvedArgument.getArgumentExpressions(); + for (JetExpression argumentExpression : argumentExpressions) { + JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(candidateCall.getTrace()); + JetType type = temporaryServices.getType(scope, argumentExpression, parameterType); + if (type == null) { + candidateCall.argumentHasNoType(); + } + else if (!semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) { +// VariableDescriptor variableDescriptor = AutoCastUtils.getVariableDescriptorFromSimpleName(temporaryTrace.getBindingContext(), argumentExpression); +// if (variableDescriptor != null) { +// JetType autoCastType = null; +// for (JetType possibleType : dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)) { +// if (semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) { +// autoCastType = possibleType; +// break; +// } +// } +// if (autoCastType != null) { +// if (AutoCastUtils.isAutoCastable(variableDescriptor)) { +// temporaryTrace.record(AUTOCAST, argumentExpression, autoCastType); +// } +// else { +// temporaryTrace.report(AUTOCAST_IMPOSSIBLE.on(argumentExpression, autoCastType, variableDescriptor)); +// result = false; +// } +// } +// } +// else { + result = OTHER_ERROR; + } + } } - return true; + return result; } @NotNull - private OverloadResolutionResult computeResultAndReportErrors(BindingTrace trace, TracingStrategy tracing, Map successfulCandidates, Set failedCandidates, Set dirtyCandidates, Map traces) { + private OverloadResolutionResults computeResultAndReportErrors( + BindingTrace trace, + TracingStrategy tracing, + Set> successfulCandidates, + Set> failedCandidates) { // TODO : maybe it's better to filter overrides out first, and only then look for the maximally specific if (successfulCandidates.size() > 0) { - if (successfulCandidates.size() != 1) { - Map cleanCandidates = Maps.newLinkedHashMap(successfulCandidates); - cleanCandidates.keySet().removeAll(dirtyCandidates); - if (cleanCandidates.isEmpty()) { - cleanCandidates = successfulCandidates; - } - D maximallySpecific = overloadingConflictResolver.findMaximallySpecific(cleanCandidates, traces, false); - if (maximallySpecific != null) { - return OverloadResolutionResult.success(maximallySpecific); - } - - D maximallySpecificGenericsDiscriminated = overloadingConflictResolver.findMaximallySpecific(cleanCandidates, traces, true); - if (maximallySpecificGenericsDiscriminated != null) { - return OverloadResolutionResult.success(maximallySpecificGenericsDiscriminated); - } - - Set noOverrides = OverridingUtil.filterOverrides(successfulCandidates.keySet()); - if (dirtyCandidates.isEmpty()) { -// tracing.reportOverallResolutionError(trace, "Overload resolution ambiguity: " -// + makeErrorMessageForMultipleDescriptors(noOverrides)); - tracing.ambiguity(trace, noOverrides); - } - - tracing.recordAmbiguity(trace, noOverrides); - - return OverloadResolutionResult.ambiguity(noOverrides); - } - else { - Map.Entry entry = successfulCandidates.entrySet().iterator().next(); - D functionDescriptor = entry.getKey(); - D result = entry.getValue(); - - TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor); - temporaryTrace.commit(); - return OverloadResolutionResult.success(result); - } + return chooseAndReportMaximallySpecific(trace, tracing, successfulCandidates); } else if (!failedCandidates.isEmpty()) { if (failedCandidates.size() != 1) { - Set noOverrides = OverridingUtil.filterOverrides(failedCandidates); + Set> weakErrors = Sets.newLinkedHashSet(); + for (ResolvedCall candidate : failedCandidates) { + if (candidate.getStatus().isWeakError()) { + weakErrors.add(candidate); + } + } + if (!weakErrors.isEmpty()) { + OverloadResolutionResults results = chooseAndReportMaximallySpecific(trace, tracing, weakErrors); + if (results.isSuccess()) { + return OverloadResolutionResults.singleFailedCandidate(results.getResult()); + } + + return OverloadResolutionResults.manyFailedCandidates(results.getResults()); + } + + Set> noOverrides = OverridingUtil.filterOverrides(failedCandidates, MAP_TO_CANDIDATE); if (noOverrides.size() != 1) { // tracing.reportOverallResolutionError(trace, "None of the following functions can be called with the arguments supplied: " // + makeErrorMessageForMultipleDescriptors(noOverrides)); tracing.noneApplicable(trace, noOverrides); tracing.recordAmbiguity(trace, noOverrides); - return OverloadResolutionResult.manyFailedCandidates(noOverrides); + return OverloadResolutionResults.manyFailedCandidates(noOverrides); } failedCandidates = noOverrides; } - D functionDescriptor = failedCandidates.iterator().next(); - TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor); - temporaryTrace.commit(); - return OverloadResolutionResult.singleFailedCandidate(failedCandidates.iterator().next()); + ResolvedCall failed = failedCandidates.iterator().next(); + failed.getTrace().commit(); + return OverloadResolutionResults.singleFailedCandidate(failed); } else { tracing.unresolvedReference(trace); - return OverloadResolutionResult.nameNotFound(); + return OverloadResolutionResults.nameNotFound(); } } - private boolean checkValueArgumentTypes(JetScope scope, JetTypeInferrer.Services temporaryServices, Map argumentsToParameters, Flag dirty, Function parameterMap) { - boolean result = true; - for (Map.Entry entry : argumentsToParameters.entrySet()) { - ValueArgument valueArgument = entry.getKey(); - ValueParameterDescriptor valueParameterDescriptor = entry.getValue(); - - ValueParameterDescriptor substitutedParameter = parameterMap.apply(valueParameterDescriptor); - - assert substitutedParameter != null; - - JetType parameterType = substitutedParameter.getOutType(); - JetExpression argumentExpression = valueArgument.getArgumentExpression(); - if (argumentExpression != null) { - JetType type = temporaryServices.getType(scope, argumentExpression, parameterType); - if (type == null) { - dirty.setValue(true); - } - else if (!semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) { - result = false; + private OverloadResolutionResults chooseAndReportMaximallySpecific(BindingTrace trace, TracingStrategy tracing, Set> candidates) { + if (candidates.size() != 1) { + Set> cleanCandidates = Sets.newLinkedHashSet(candidates); + boolean allClean = true; + for (Iterator> iterator = cleanCandidates.iterator(); iterator.hasNext(); ) { + ResolvedCall candidate = iterator.next(); + if (candidate.isDirty()) { + iterator.remove(); + allClean = false; } } + + if (cleanCandidates.isEmpty()) { + cleanCandidates = candidates; + } + ResolvedCall maximallySpecific = overloadingConflictResolver.findMaximallySpecific(cleanCandidates, false); + if (maximallySpecific != null) { + return OverloadResolutionResults.success(maximallySpecific); + } + + ResolvedCall maximallySpecificGenericsDiscriminated = overloadingConflictResolver.findMaximallySpecific(cleanCandidates, true); + if (maximallySpecificGenericsDiscriminated != null) { + return OverloadResolutionResults.success(maximallySpecificGenericsDiscriminated); + } + + Set> noOverrides = OverridingUtil.filterOverrides(candidates, MAP_TO_RESULT); + if (allClean) { +// tracing.reportOverallResolutionError(trace, "Overload resolution ambiguity: " +// + makeErrorMessageForMultipleDescriptors(noOverrides)); + tracing.ambiguity(trace, noOverrides); + } + + tracing.recordAmbiguity(trace, noOverrides); + + return OverloadResolutionResults.ambiguity(noOverrides); + } + else { + ResolvedCall result = candidates.iterator().next(); + + TemporaryBindingTrace temporaryTrace = result.getTrace(); + temporaryTrace.commit(); + return OverloadResolutionResults.success(result); } - return result; } public void checkGenericBoundsInAFunctionCall(List jetTypeArguments, List typeArguments, CallableDescriptor functionDescriptor, BindingTrace trace) { @@ -618,26 +747,25 @@ public class CallResolver { } @NotNull - public OverloadResolutionResult resolveExactSignature(@NotNull JetScope scope, @NotNull ReceiverDescriptor receiver, @NotNull String name, @NotNull List parameterTypes) { - List result = findCandidatesByExactSignature(scope, receiver, name, parameterTypes); + public OverloadResolutionResults resolveExactSignature(@NotNull JetScope scope, @NotNull ReceiverDescriptor receiver, @NotNull String name, @NotNull List parameterTypes) { + List> result = findCandidatesByExactSignature(scope, receiver, name, parameterTypes); BindingTraceContext trace = new BindingTraceContext(); TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create(trace); - Map traces = Maps.newHashMap(); - Map candidates = Maps.newLinkedHashMap(); - for (FunctionDescriptor functionDescriptor : result) { - candidates.put(functionDescriptor, functionDescriptor); - traces.put(functionDescriptor, temporaryBindingTrace); + Set> candidates = Sets.newLinkedHashSet(); + for (ResolvedCall call : result) { + call.setTrace(temporaryBindingTrace); + candidates.add(call); } - return computeResultAndReportErrors(trace, TracingStrategy.EMPTY, candidates, Collections.emptySet(), Collections.emptySet(), traces); + return computeResultAndReportErrors(trace, TracingStrategy.EMPTY, candidates, Collections.>emptySet()); } - private List findCandidatesByExactSignature(JetScope scope, ReceiverDescriptor receiver, String name, List parameterTypes) { - List result = Lists.newArrayList(); - if (receiver != NO_RECEIVER) { - Set extensionFunctionDescriptors = scope.getFunctions(name); - List nonlocal = Lists.newArrayList(); - List local = Lists.newArrayList(); + private List> findCandidatesByExactSignature(JetScope scope, ReceiverDescriptor receiver, String name, List parameterTypes) { + List> result = Lists.newArrayList(); + if (receiver.exists()) { + Collection> extensionFunctionDescriptors = ResolvedCall.convertCollection(scope.getFunctions(name)); + List> nonlocal = Lists.newArrayList(); + List> local = Lists.newArrayList(); TaskPrioritizer.splitLexicallyLocalDescriptors(extensionFunctionDescriptors, scope.getContainingDeclaration(), local, nonlocal); @@ -645,7 +773,7 @@ public class CallResolver { return result; } - Set functionDescriptors = receiver.getType().getMemberScope().getFunctions(name); + Collection> functionDescriptors = ResolvedCall.convertCollection(receiver.getType().getMemberScope().getFunctions(name)); if (lookupExactSignature(functionDescriptors, parameterTypes, result)) { return result; @@ -654,32 +782,34 @@ public class CallResolver { return result; } else { - lookupExactSignature(scope.getFunctions(name), parameterTypes, result); + lookupExactSignature(ResolvedCall.convertCollection(scope.getFunctions(name)), parameterTypes, result); return result; } } - private boolean lookupExactSignature(Set candidates, List parameterTypes, List result) { + private boolean lookupExactSignature(Collection> candidates, List parameterTypes, List> result) { boolean found = false; - for (FunctionDescriptor functionDescriptor : candidates) { - if (functionDescriptor.getReceiver() != NO_RECEIVER) continue; + for (ResolvedCall resolvedCall : candidates) { + FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor(); + if (functionDescriptor.getReceiverParameter().exists()) continue; if (!functionDescriptor.getTypeParameters().isEmpty()) continue; if (!checkValueParameters(functionDescriptor, parameterTypes)) continue; - result.add(functionDescriptor); + result.add(resolvedCall); found = true; } return found; } - private boolean findExtensionFunctions(Collection candidates, ReceiverDescriptor receiver, List parameterTypes, List result) { + private boolean findExtensionFunctions(Collection> candidates, ReceiverDescriptor receiver, List parameterTypes, List> result) { boolean found = false; - for (FunctionDescriptor functionDescriptor : candidates) { - ReceiverDescriptor functionReceiver = functionDescriptor.getReceiver(); - if (functionReceiver == NO_RECEIVER) continue; + for (ResolvedCall resolvedCall : candidates) { + FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor(); + ReceiverDescriptor functionReceiver = functionDescriptor.getReceiverParameter(); + if (!functionReceiver.exists()) continue; if (!functionDescriptor.getTypeParameters().isEmpty()) continue; if (!semanticServices.getTypeChecker().isSubtypeOf(receiver.getType(), functionReceiver.getType())) continue; if (!checkValueParameters(functionDescriptor, parameterTypes))continue; - result.add(functionDescriptor); + result.add(resolvedCall); found = true; } return found; @@ -695,129 +825,4 @@ public class CallResolver { } return true; } - - private static TaskPrioritizer FUNCTION_TASK_PRIORITIZER = new TaskPrioritizer() { - - @NotNull - @Override - protected Collection getNonExtensionsByName(JetScope scope, String name) { - Set functions = Sets.newLinkedHashSet(scope.getFunctions(name)); - for (Iterator iterator = functions.iterator(); iterator.hasNext(); ) { - FunctionDescriptor functionDescriptor = iterator.next(); - if (functionDescriptor.getReceiver() != NO_RECEIVER) { - iterator.remove(); - } - } - addConstructors(scope, name, functions); - - addVariableAsFunction(scope, name, functions, false); - return functions; - } - - @NotNull - @Override - protected Collection getMembersByName(@NotNull ReceiverDescriptor receiver, String name) { - JetScope receiverScope = receiver.getType().getMemberScope(); - Set members = Sets.newHashSet(receiverScope.getFunctions(name)); - addConstructors(receiverScope, name, members); - addVariableAsFunction(receiverScope, name, members, false); - return members; - } - - @NotNull - @Override - protected Collection getExtensionsByName(JetScope scope, String name) { - Set extensionFunctions = Sets.newHashSet(scope.getFunctions(name)); - for (Iterator iterator = extensionFunctions.iterator(); iterator.hasNext(); ) { - FunctionDescriptor descriptor = iterator.next(); - if (descriptor.getReceiver() == NO_RECEIVER) { - iterator.remove(); - } - } - addVariableAsFunction(scope, name, extensionFunctions, true); - return extensionFunctions; - } - - @NotNull - @Override - protected ResolutionTask createTask(@NotNull ReceiverDescriptor receiver, Call call, Collection candidates) { - return new ResolutionTask(candidates, receiver, call); - } - - private void addConstructors(JetScope scope, String name, Collection functions) { - ClassifierDescriptor classifier = scope.getClassifier(name); - if (classifier instanceof ClassDescriptor && !ErrorUtils.isError(classifier.getTypeConstructor())) { - ClassDescriptor classDescriptor = (ClassDescriptor) classifier; - functions.addAll(classDescriptor.getConstructors()); - } - } - - private void addVariableAsFunction(JetScope scope, String name, Set functions, boolean receiverNeeded) { - VariableDescriptor variable = scope.getVariable(name); - if (variable != null && variable.getReceiver() == NO_RECEIVER) { - JetType outType = variable.getOutType(); - if (outType != null && JetStandardClasses.isFunctionType(outType)) { - VariableAsFunctionDescriptor functionDescriptor = VariableAsFunctionDescriptor.create(variable); - if ((functionDescriptor.getReceiver() != NO_RECEIVER) == receiverNeeded) { - functions.add(functionDescriptor); - } - } - } - } - }; - - private static TaskPrioritizer PROPERTY_TASK_PRIORITIZER = new TaskPrioritizer() { - - @NotNull - @Override - protected Collection getNonExtensionsByName(JetScope scope, String name) { - VariableDescriptor variable = scope.getVariable(name); - if (variable != null && variable.getReceiver() == NO_RECEIVER) { - return Collections.singleton(variable); - } - return Collections.emptyList(); - } - - @NotNull - @Override - protected Collection getMembersByName(@NotNull ReceiverDescriptor receiver, String name) { - VariableDescriptor variable = receiver.getType().getMemberScope().getVariable(name); - if (variable != null) { - return Collections.singleton(variable); - } - return Collections.emptyList(); - } - - @NotNull - @Override - protected Collection getExtensionsByName(JetScope scope, String name) { - VariableDescriptor variable = scope.getVariable(name); - if (variable != null && variable.getReceiver() != NO_RECEIVER) { - return Collections.singleton(variable); - } - return Collections.emptyList(); - } - - @NotNull - @Override - protected ResolutionTask createTask(@NotNull ReceiverDescriptor receiver, Call call, Collection candidates) { - return new ResolutionTask(candidates, receiver, call); - } - }; - - private static class Flag { - private boolean flag; - - public Flag(boolean flag) { - this.flag = flag; - } - - public boolean getValue() { - return flag; - } - - public void setValue(boolean flag) { - this.flag = flag; - } - } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DefaultValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DefaultValueArgument.java new file mode 100644 index 00000000000..2303269f5be --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DefaultValueArgument.java @@ -0,0 +1,22 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetExpression; + +import java.util.Collections; +import java.util.List; + +/** +* @author abreslav +*/ +public class DefaultValueArgument implements ResolvedValueArgument { + public static final DefaultValueArgument DEFAULT = new DefaultValueArgument(); + + private DefaultValueArgument() {} + + @NotNull + @Override + public List getArgumentExpressions() { + return Collections.emptyList(); //throw new UnsupportedOperationException("Look into the default value of the parameter"); + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionValueArgument.java new file mode 100644 index 00000000000..02abdc635eb --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionValueArgument.java @@ -0,0 +1,32 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.psi.JetExpression; + +import java.util.Collections; +import java.util.List; + +/** +* @author abreslav +*/ +public class ExpressionValueArgument implements ResolvedValueArgument { + private final JetExpression expression; + + public ExpressionValueArgument(@Nullable JetExpression expression) { + this.expression = expression; + } + + // Nullable when something like f(a, , b) was in the source code + @Nullable + public JetExpression getExpression() { + return expression; + } + + @NotNull + @Override + public List getArgumentExpressions() { + if (expression == null) return Collections.emptyList(); + return Collections.singletonList(expression); + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadResolutionResult.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadResolutionResult.java deleted file mode 100644 index 799d001616b..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadResolutionResult.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.jetbrains.jet.lang.resolve.calls; - -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; -import java.util.Collections; -import java.util.Set; - -/** -* @author abreslav -*/ -public class OverloadResolutionResult { - public enum Code { - SUCCESS(true), - NAME_NOT_FOUND(false), - SINGLE_CANDIDATE_ARGUMENT_MISMATCH(false), - AMBIGUITY(false), - MANY_FAILED_CANDIDATES(false); - - private final boolean success; - - Code(boolean success) { - this.success = success; - } - - boolean isSuccess() { - return success; - } - - } - - public static OverloadResolutionResult success(@NotNull D descriptor) { - return new OverloadResolutionResult(Code.SUCCESS, Collections.singleton(descriptor)); - } - - public static OverloadResolutionResult nameNotFound() { - return new OverloadResolutionResult(Code.NAME_NOT_FOUND, Collections.emptyList()); - } - - public static OverloadResolutionResult singleFailedCandidate(D candidate) { - return new OverloadResolutionResult(Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH, Collections.singleton(candidate)); - } - public static OverloadResolutionResult manyFailedCandidates(Set failedCandidates) { - return new OverloadResolutionResult(Code.MANY_FAILED_CANDIDATES, failedCandidates); - } - - public static OverloadResolutionResult ambiguity(Collection descriptors) { - return new OverloadResolutionResult(Code.AMBIGUITY, descriptors); - } - - private final Collection descriptors; - - private final Code resultCode; - - public OverloadResolutionResult(@NotNull Code resultCode, @NotNull Collection descriptors) { - this.descriptors = descriptors; - this.resultCode = resultCode; - - } - - @NotNull - public Collection getDescriptors() { - return descriptors; - } - - @NotNull - public D getDescriptor() { - assert singleDescriptor(); - return descriptors.iterator().next(); - } - - @NotNull - public Code getResultCode() { - return resultCode; - } - - public boolean isSuccess() { - return resultCode.isSuccess(); - } - - public boolean singleDescriptor() { - return isSuccess() || resultCode == Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH; - } - - public boolean isNothing() { - return resultCode == Code.NAME_NOT_FOUND; - } - - public boolean isAmbiguity() { - return resultCode == Code.AMBIGUITY; - } - - public OverloadResolutionResult newContents(@NotNull Collection functionDescriptors) { - return new OverloadResolutionResult(resultCode, functionDescriptors); - } -} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadResolutionResults.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadResolutionResults.java new file mode 100644 index 00000000000..e93b7a0a2db --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadResolutionResults.java @@ -0,0 +1,94 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.CallableDescriptor; + +import java.util.Collection; +import java.util.Collections; + +/** +* @author abreslav +*/ +public class OverloadResolutionResults { + public enum Code { + SUCCESS(true), + NAME_NOT_FOUND(false), + SINGLE_CANDIDATE_ARGUMENT_MISMATCH(false), + AMBIGUITY(false), + MANY_FAILED_CANDIDATES(false); + + private final boolean success; + + Code(boolean success) { + this.success = success; + } + + boolean isSuccess() { + return success; + } + + } + + public static OverloadResolutionResults success(@NotNull ResolvedCall descriptor) { + return new OverloadResolutionResults(Code.SUCCESS, Collections.singleton(descriptor)); + } + + public static OverloadResolutionResults nameNotFound() { + return new OverloadResolutionResults(Code.NAME_NOT_FOUND, Collections.>emptyList()); + } + + public static OverloadResolutionResults singleFailedCandidate(ResolvedCall candidate) { + return new OverloadResolutionResults(Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH, Collections.singleton(candidate)); + } + public static OverloadResolutionResults manyFailedCandidates(Collection> failedCandidates) { + return new OverloadResolutionResults(Code.MANY_FAILED_CANDIDATES, failedCandidates); + } + + public static OverloadResolutionResults ambiguity(Collection> descriptors) { + return new OverloadResolutionResults(Code.AMBIGUITY, descriptors); + } + + private final Collection> results; + private final Code resultCode; + + private OverloadResolutionResults(@NotNull Code resultCode, @NotNull Collection> results) { + this.results = results; + this.resultCode = resultCode; + } + + @NotNull + public Collection> getResults() { + return results; + } + + @NotNull + public ResolvedCall getResult() { + assert singleDescriptor(); + return results.iterator().next(); + } + + @NotNull + public Code getResultCode() { + return resultCode; + } + + public boolean isSuccess() { + return resultCode.isSuccess(); + } + + public boolean singleDescriptor() { + return isSuccess() || resultCode == Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH; + } + + public boolean isNothing() { + return resultCode == Code.NAME_NOT_FOUND; + } + + public boolean isAmbiguity() { + return resultCode == Code.AMBIGUITY; + } +// +// public OverloadResolutionResults newContents(@NotNull Collection functionDescriptors) { +// return new OverloadResolutionResults(resultCode, functionDescriptors); +// } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java index 127cf37efec..dc12c9ab9bc 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.lang.resolve.calls; -import com.google.common.collect.Maps; +import gnu.trove.THashSet; +import gnu.trove.TObjectHashingStrategy; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.JetSemanticServices; @@ -8,13 +9,12 @@ import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.OverridingUtil; -import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.JetStandardLibrary; import org.jetbrains.jet.lang.types.JetType; import java.util.List; -import java.util.Map; +import java.util.Set; /** * @author abreslav @@ -28,22 +28,35 @@ public class OverloadingConflictResolver { } @Nullable - public Descriptor findMaximallySpecific(Map candidates, Map traces, boolean discriminateGenericDescriptors) { - Map maximallySpecific = Maps.newHashMap(); + public ResolvedCall findMaximallySpecific(Set> candidates, boolean discriminateGenericDescriptors) { + // Different autocasts may lead to the same candidate descriptor wrapped into different ResolvedCall objects + Set> maximallySpecific = new THashSet>(new TObjectHashingStrategy>() { + @Override + public boolean equals(ResolvedCall o1, ResolvedCall o2) { + return o1 == null ? o2 == null : o1.getResultingDescriptor().equals(o2.getResultingDescriptor()); + } + + @Override + public int computeHashCode(ResolvedCall object) { + return object == null ? 0 : object.getResultingDescriptor().hashCode(); + } + }); meLoop: - for (Map.Entry myEntry : candidates.entrySet()) { - Descriptor me = myEntry.getValue(); - TemporaryBindingTrace myTrace = traces.get(myEntry.getKey()); - for (Descriptor other : candidates.values()) { + for (ResolvedCall candidateCall : candidates) { + D me = candidateCall.getResultingDescriptor(); + for (ResolvedCall otherCall : candidates) { + D other = otherCall.getResultingDescriptor(); if (other == me) continue; - if (!moreSpecific(me, other, discriminateGenericDescriptors) || moreSpecific(other, me, discriminateGenericDescriptors)) continue meLoop; + if (!moreSpecific(me, other, discriminateGenericDescriptors) || moreSpecific(other, me, discriminateGenericDescriptors)) { + continue meLoop; + } } - maximallySpecific.put(me, myTrace); + maximallySpecific.add(candidateCall); } if (maximallySpecific.size() == 1) { - Map.Entry result = maximallySpecific.entrySet().iterator().next(); - result.getValue().commit(); - return result.getKey(); + ResolvedCall result = maximallySpecific.iterator().next(); + result.getTrace().commit(); + return result; } return null; } @@ -59,9 +72,9 @@ public class OverloadingConflictResolver { if (OverridingUtil.overrides(f, g)) return true; if (OverridingUtil.overrides(g, f)) return false; - ReceiverDescriptor receiverOfF = f.getReceiver(); - ReceiverDescriptor receiverOfG = g.getReceiver(); - if (f.getReceiver().exists() && g.getReceiver().exists()) { + ReceiverDescriptor receiverOfF = f.getReceiverParameter(); + ReceiverDescriptor receiverOfG = g.getReceiverParameter(); + if (f.getReceiverParameter().exists() && g.getReceiverParameter().exists()) { if (!typeMoreSpecific(receiverOfF.getType(), receiverOfG.getType())) return false; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionStatus.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionStatus.java new file mode 100644 index 00000000000..7c9c5406285 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionStatus.java @@ -0,0 +1,35 @@ +package org.jetbrains.jet.lang.resolve.calls; + +/** + * @author abreslav + */ +public enum ResolutionStatus { + UNKNOWN_STATUS, + UNSAFE_CALL_ERROR, + OTHER_ERROR, + SUCCESS(true); + + private final boolean success; + + private ResolutionStatus(boolean success) { + this.success = success; + } + + private ResolutionStatus() { + this(false); + } + + public boolean isSuccess() { + return success; + } + + public ResolutionStatus combine(ResolutionStatus other) { + if (this.isSuccess()) return other; + if (this.isWeakError() && !other.isSuccess()) return other; + return this; + } + + public boolean isWeakError() { + return this == UNSAFE_CALL_ERROR; + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java index c369d8aa730..25e01c32074 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java @@ -1,81 +1,53 @@ package org.jetbrains.jet.lang.resolve.calls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.psi.Call; -import org.jetbrains.jet.lang.psi.JetExpression; -import org.jetbrains.jet.lang.psi.JetTypeProjection; -import org.jetbrains.jet.lang.psi.ValueArgument; import org.jetbrains.jet.lang.resolve.BindingTrace; -import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; -import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.DataFlowInfo; import java.util.Collection; -import java.util.List; /** * @author abreslav */ -/*package*/ class ResolutionTask { - private final Collection candidates; - private final ReceiverDescriptor receiver; - private final List typeArguments; - private final List valueArguments; - private final List functionLiteralArguments; +/*package*/ class ResolutionTask { + private final Call call; + private final Collection> candidates; + private final DataFlowInfo dataFlowInfo; private DescriptorCheckStrategy checkingStrategy; - public ResolutionTask( - @NotNull Collection candidates, - @NotNull ReceiverDescriptor receiver, - @NotNull List typeArguments, - @NotNull List valueArguments, - @NotNull List functionLiteralArguments) { - this.candidates = candidates; - this.receiver = receiver; - this.typeArguments = typeArguments; - this.valueArguments = valueArguments; - this.functionLiteralArguments = functionLiteralArguments; - } public ResolutionTask( - @NotNull Collection candidates, - @NotNull ReceiverDescriptor receiver, - @NotNull Call call + @NotNull Collection> candidates, + @NotNull Call call, + @NotNull DataFlowInfo dataFlowInfo ) { - this(candidates, receiver, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments()); + this.candidates = candidates; + this.call = call; + this.dataFlowInfo = dataFlowInfo; } @NotNull - public Collection getCandidates() { + public DataFlowInfo getDataFlowInfo() { + return dataFlowInfo; + } + + @NotNull + public Collection> getCandidates() { return candidates; } @NotNull - public ReceiverDescriptor getReceiver() { - return receiver; + public Call getCall() { + return call; } - @NotNull - public List getTypeArguments() { - return typeArguments; - } - - @NotNull - public List getValueArguments() { - return valueArguments; - } - - @NotNull - public List getFunctionLiteralArguments() { - return functionLiteralArguments; - } - public void setCheckingStrategy(DescriptorCheckStrategy strategy) { checkingStrategy = strategy; } - public boolean performAdvancedChecks(Descriptor descriptor, BindingTrace trace, TracingStrategy tracing) { + public boolean performAdvancedChecks(D descriptor, BindingTrace trace, TracingStrategy tracing) { if (checkingStrategy != null && !checkingStrategy.performAdvancedChecks(descriptor, trace, tracing)) { return false; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java new file mode 100644 index 00000000000..73021e8890f --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java @@ -0,0 +1,147 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.intellij.util.Function; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.CallableDescriptor; +import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; +import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; +import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.types.JetType; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static org.jetbrains.jet.lang.resolve.calls.ResolutionStatus.UNKNOWN_STATUS; +import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER; + +/** + * @author abreslav + */ +public class ResolvedCall { + + public static final Function, CallableDescriptor> MAP_TO_CANDIDATE = new Function, CallableDescriptor>() { + @Override + public CallableDescriptor fun(ResolvedCall resolvedCall) { + return resolvedCall.getCandidateDescriptor(); + } + }; + + public static final Function, CallableDescriptor> MAP_TO_RESULT = new Function, CallableDescriptor>() { + @Override + public CallableDescriptor fun(ResolvedCall resolvedCall) { + return resolvedCall.getResultingDescriptor(); + } + }; + + @NotNull + public static ResolvedCall create(@NotNull D descriptor) { + return new ResolvedCall(descriptor); + } + + @NotNull + public static List> convertCollection(@NotNull Collection descriptors) { + List> result = Lists.newArrayList(); + for (D descriptor : descriptors) { + result.add(create(descriptor)); + } + return result; + } + + private final D candidateDescriptor; + private D resultingDescriptor; // Probably substituted + private ReceiverDescriptor thisObject = NO_RECEIVER; // receiver object of a method + private ReceiverDescriptor receiverArgument = NO_RECEIVER; // receiver of an extension function + private final Map typeArguments = Maps.newLinkedHashMap(); + private final Map autoCasts = Maps.newHashMap(); + private final Map valueArguments = Maps.newHashMap(); + private boolean someArgumentHasNoType = false; + private TemporaryBindingTrace trace; + private ResolutionStatus status = UNKNOWN_STATUS; + + private ResolvedCall(@NotNull D candidateDescriptor) { + this.candidateDescriptor = candidateDescriptor; + } + + @NotNull + public ResolutionStatus getStatus() { + return status; + } + + public void setStatus(@NotNull ResolutionStatus status) { + this.status = status; + } + + @NotNull + public TemporaryBindingTrace getTrace() { + return trace; + } + + public void setTrace(@NotNull TemporaryBindingTrace trace) { + this.trace = trace; + } + + @NotNull + public D getCandidateDescriptor() { + return candidateDescriptor; + } + + @NotNull + public D getResultingDescriptor() { + return resultingDescriptor == null ? candidateDescriptor : resultingDescriptor; + } + + public ResolvedCall setResultingDescriptor(@NotNull D resultingDescriptor) { + this.resultingDescriptor = resultingDescriptor; + return this; + } + + public void recordTypeArgument(@NotNull TypeParameterDescriptor typeParameter, @NotNull JetType typeArgument) { + assert !typeArguments.containsKey(typeParameter); + typeArguments.put(typeParameter, typeArgument); + } + + public void recordValueArgument(@NotNull ValueParameterDescriptor valueParameter, @NotNull ResolvedValueArgument valueArgument) { + assert !valueArguments.containsKey(valueParameter); + valueArguments.put(valueParameter, valueArgument); + } + + public void autoCastValueArgument(@NotNull ValueParameterDescriptor parameter, @NotNull JetType target) { + assert !autoCasts.containsKey(parameter); + autoCasts.put(parameter, target); + } + + @NotNull + public ReceiverDescriptor getReceiverArgument() { + return receiverArgument; + } + + public void setReceiverArgument(@NotNull ReceiverDescriptor receiverParameter) { + this.receiverArgument = receiverParameter; + } + + @NotNull + public ReceiverDescriptor getThisObject() { + return thisObject; + } + + public void setThisObject(@NotNull ReceiverDescriptor thisObject) { + this.thisObject = thisObject; + } + + @NotNull + public Map getValueArguments() { + return valueArguments; + } + + public void argumentHasNoType() { + this.someArgumentHasNoType = true; + } + + public boolean isDirty() { + return someArgumentHasNoType; + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedValueArgument.java new file mode 100644 index 00000000000..6aa676ca955 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedValueArgument.java @@ -0,0 +1,15 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetExpression; + +import java.util.List; + +/** +* @author abreslav +*/ +public interface ResolvedValueArgument { + @NotNull + List getArgumentExpressions(); + +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java index c14a3c00e9e..2711c751b4f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java @@ -2,31 +2,39 @@ package org.jetbrains.jet.lang.resolve.calls; import com.google.common.collect.Lists; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.CallableDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.psi.Call; -import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.types.DataFlowInfo; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.JetTypeChecker; +import org.jetbrains.jet.lang.types.NamespaceType; import java.util.Collection; +import java.util.Collections; import java.util.List; +import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER; + /** * @author abreslav */ /*package*/ abstract class TaskPrioritizer { - public static void splitLexicallyLocalDescriptors( - Collection allDescriptors, DeclarationDescriptor containerOfTheCurrentLocality, List local, List nonlocal) { + public static void splitLexicallyLocalDescriptors( + Collection> allDescriptors, DeclarationDescriptor containerOfTheCurrentLocality, Collection> local, Collection> nonlocal) { - for (T descriptor : allDescriptors) { - if (isLocal(containerOfTheCurrentLocality, descriptor)) { - local.add(descriptor); + for (ResolvedCall resolvedCall : allDescriptors) { + if (isLocal(containerOfTheCurrentLocality, resolvedCall.getCandidateDescriptor())) { + local.add(resolvedCall); } else { - nonlocal.add(descriptor); + nonlocal.add(resolvedCall); } } } @@ -43,7 +51,7 @@ import java.util.List; * * local extension prevail over members (and members prevail over all non-local extensions) */ - public static boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) { + private static boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) { if (candidate instanceof ValueParameterDescriptor) { return true; } @@ -62,67 +70,132 @@ import java.util.List; return false; } - public List> computePrioritizedTasks(@NotNull JetScope scope, @NotNull ReceiverDescriptor receiver, @NotNull Call call, @NotNull String name) { + public List> computePrioritizedTasks(@NotNull JetScope scope, @NotNull Call call, @NotNull String name, @NotNull BindingContext bindingContext, @NotNull DataFlowInfo dataFlowInfo) { List> result = Lists.newArrayList(); - doComputeTasks(scope, receiver, call, name, result); + + ReceiverDescriptor explicitReceiver = call.getExplicitReceiver(); + if (explicitReceiver.exists() && explicitReceiver.getType() instanceof NamespaceType) { + scope = explicitReceiver.getType().getMemberScope(); + explicitReceiver = NO_RECEIVER; + } + doComputeTasks(scope, explicitReceiver, call, name, result, AutoCastService.NO_AUTO_CASTS); + + ReceiverDescriptor receiverToCast = explicitReceiver.exists() ? explicitReceiver : scope.getImplicitReceiver(); + if (receiverToCast.exists()) { + doComputeTasks(scope, receiverToCast, call, name, result, new AutoCastServiceImpl(dataFlowInfo, bindingContext)); + } return result; } - private void doComputeTasks(JetScope scope, ReceiverDescriptor receiver, Call call, String name, List> result) { + private void doComputeTasks(JetScope scope, ReceiverDescriptor receiver, Call call, String name, List> result, @NotNull AutoCastService autoCastService) { + DataFlowInfo dataFlowInfo = autoCastService.getDataFlowInfo(); List implicitReceivers = Lists.newArrayList(); scope.getImplicitReceiversHierarchy(implicitReceivers); - if (receiver != ReceiverDescriptor.NO_RECEIVER) { - Collection extensionFunctions = getExtensionsByName(scope, name); - List nonlocals = Lists.newArrayList(); - List locals = Lists.newArrayList(); + if (receiver.exists()) { + List variantsForExplicitReceiver = autoCastService.getVariantsForReceiver(receiver); + + Collection> extensionFunctions = convertWithImpliedThis(scope, variantsForExplicitReceiver, getExtensionsByName(scope, name)); + List> nonlocals = Lists.newArrayList(); + List> locals = Lists.newArrayList(); //noinspection unchecked,RedundantTypeArguments TaskPrioritizer.splitLexicallyLocalDescriptors(extensionFunctions, scope.getContainingDeclaration(), locals, nonlocals); - Collection members = getMembersByName(receiver, name); + Collection> members = Lists.newArrayList(); + for (ReceiverDescriptor variant : variantsForExplicitReceiver) { + Collection membersForThisVariant = getMembersByName(variant.getType(), name); + convertWithReceivers(membersForThisVariant, Collections.singletonList(variant), Collections.singletonList(NO_RECEIVER), members); + } - addTask(result, receiver, call, locals); - addTask(result, ReceiverDescriptor.NO_RECEIVER, call, members); + addTask(result, call, locals, dataFlowInfo); + addTask(result, call, members, dataFlowInfo); for (ReceiverDescriptor implicitReceiver : implicitReceivers) { Collection memberExtensions = getExtensionsByName(implicitReceiver.getType().getMemberScope(), name); - addTask(result, receiver, call, memberExtensions); + List variantsForImplicitReceiver = autoCastService.getVariantsForReceiver(implicitReceiver); + addTask(result, call, convertWithReceivers(memberExtensions, variantsForImplicitReceiver, variantsForExplicitReceiver), dataFlowInfo); } - addTask(result, receiver, call, nonlocals); + addTask(result, call, nonlocals, dataFlowInfo); } else { - Collection functions = getNonExtensionsByName(scope, name); + Collection> functions = convertWithImpliedThis(scope, Collections.singletonList(receiver), getNonExtensionsByName(scope, name)); - List nonlocals = Lists.newArrayList(); - List locals = Lists.newArrayList(); + List> nonlocals = Lists.newArrayList(); + List> locals = Lists.newArrayList(); //noinspection unchecked,RedundantTypeArguments TaskPrioritizer.splitLexicallyLocalDescriptors(functions, scope.getContainingDeclaration(), locals, nonlocals); - addTask(result, receiver, call, locals); + addTask(result, call, locals, dataFlowInfo); for (ReceiverDescriptor implicitReceiver : implicitReceivers) { - doComputeTasks(scope, implicitReceiver, call, name, result); + doComputeTasks(scope, implicitReceiver, call, name, result, autoCastService); } - addTask(result, receiver, call, nonlocals); + addTask(result, call, nonlocals, dataFlowInfo); } } + private Collection> convertWithReceivers(Collection descriptors, Iterable thisObjects, Iterable receiverParameters) { + Collection> result = Lists.newArrayList(); + convertWithReceivers(descriptors, thisObjects, receiverParameters, result); + return result; + } + + private void convertWithReceivers(Collection descriptors, Iterable thisObjects, Iterable receiverParameters, Collection> result) { +// Collection> result = Lists.newArrayList(); + for (ReceiverDescriptor thisObject : thisObjects) { + for (ReceiverDescriptor receiverParameter : receiverParameters) { + for (D extension : descriptors) { + ResolvedCall resolvedCall = ResolvedCall.create(extension); + resolvedCall.setThisObject(thisObject); + resolvedCall.setReceiverArgument(receiverParameter); + result.add(resolvedCall); + } + } + } +// return result; + } + + public static Collection> convertWithImpliedThis(JetScope scope, Iterable receiverParameters, Collection descriptors) { + Collection> result = Lists.newArrayList(); + for (ReceiverDescriptor receiverParameter : receiverParameters) { + for (D extension : descriptors) { + ResolvedCall resolvedCall = ResolvedCall.create(extension); + resolvedCall.setReceiverArgument(receiverParameter); + if (setImpliedThis(scope, resolvedCall)) { + result.add(resolvedCall); + } + } + } + return result; + } + + private static boolean setImpliedThis(@NotNull JetScope scope, ResolvedCall resolvedCall) { + ReceiverDescriptor expectedThisObject = resolvedCall.getCandidateDescriptor().getExpectedThisObject(); + if (!expectedThisObject.exists()) return true; + List receivers = Lists.newArrayList(); + scope.getImplicitReceiversHierarchy(receivers); + for (ReceiverDescriptor receiver : receivers) { + if (JetTypeChecker.INSTANCE.isSubtypeOf(receiver.getType(), expectedThisObject.getType())) { + // TODO : Autocasts & nullability + resolvedCall.setThisObject(expectedThisObject); + return true; + } + } + return false; + } + + private void addTask(@NotNull List> result, @NotNull Call call, @NotNull Collection> candidates, @NotNull DataFlowInfo dataFlowInfo) { + if (candidates.isEmpty()) return; + result.add(new ResolutionTask(candidates, call, dataFlowInfo)); + } + @NotNull protected abstract Collection getNonExtensionsByName(JetScope scope, String name); @NotNull - protected abstract Collection getMembersByName(@NotNull ReceiverDescriptor receiver, String name); + protected abstract Collection getMembersByName(@NotNull JetType receiver, String name); @NotNull protected abstract Collection getExtensionsByName(JetScope scope, String name); - - private void addTask(@NotNull List> result, @NotNull ReceiverDescriptor receiver, @NotNull Call call, @NotNull Collection candidates) { - if (candidates.isEmpty()) return; - result.add(createTask(receiver, call, candidates)); - } - - @NotNull - protected abstract ResolutionTask createTask(ReceiverDescriptor receiver, Call call, Collection candidates); - } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizers.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizers.java new file mode 100644 index 00000000000..292cfd760d1 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizers.java @@ -0,0 +1,118 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import com.google.common.collect.Sets; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.types.ErrorUtils; +import org.jetbrains.jet.lang.types.JetStandardClasses; +import org.jetbrains.jet.lang.types.JetType; + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.Set; + +/** + * @author abreslav + */ +public class TaskPrioritizers { + + + /*package*/ static TaskPrioritizer FUNCTION_TASK_PRIORITIZER = new TaskPrioritizer() { + + @NotNull + @Override + protected Collection getNonExtensionsByName(JetScope scope, String name) { + Set functions = Sets.newLinkedHashSet(scope.getFunctions(name)); + for (Iterator iterator = functions.iterator(); iterator.hasNext(); ) { + FunctionDescriptor functionDescriptor = iterator.next(); + if (functionDescriptor.getReceiverParameter().exists()) { + iterator.remove(); + } + } + addConstructors(scope, name, functions); + + addVariableAsFunction(scope, name, functions, false); + return functions; + } + + @NotNull + @Override + protected Collection getMembersByName(@NotNull JetType receiverType, String name) { + JetScope receiverScope = receiverType.getMemberScope(); + Set members = Sets.newHashSet(receiverScope.getFunctions(name)); + addConstructors(receiverScope, name, members); + addVariableAsFunction(receiverScope, name, members, false); + return members; + } + + @NotNull + @Override + protected Collection getExtensionsByName(JetScope scope, String name) { + Set extensionFunctions = Sets.newHashSet(scope.getFunctions(name)); + for (Iterator iterator = extensionFunctions.iterator(); iterator.hasNext(); ) { + FunctionDescriptor descriptor = iterator.next(); + if (!descriptor.getReceiverParameter().exists()) { + iterator.remove(); + } + } + addVariableAsFunction(scope, name, extensionFunctions, true); + return extensionFunctions; + } + + private void addConstructors(JetScope scope, String name, Collection functions) { + ClassifierDescriptor classifier = scope.getClassifier(name); + if (classifier instanceof ClassDescriptor && !ErrorUtils.isError(classifier.getTypeConstructor())) { + ClassDescriptor classDescriptor = (ClassDescriptor) classifier; + functions.addAll(classDescriptor.getConstructors()); + } + } + + private void addVariableAsFunction(JetScope scope, String name, Set functions, boolean receiverNeeded) { + VariableDescriptor variable = scope.getVariable(name); + if (variable != null && !variable.getReceiverParameter().exists()) { + JetType outType = variable.getOutType(); + if (outType != null && JetStandardClasses.isFunctionType(outType)) { + VariableAsFunctionDescriptor functionDescriptor = VariableAsFunctionDescriptor.create(variable); + if ((functionDescriptor.getReceiverParameter().exists()) == receiverNeeded) { + functions.add(functionDescriptor); + } + } + } + } + }; + + /*package*/ static TaskPrioritizer PROPERTY_TASK_PRIORITIZER = new TaskPrioritizer() { + + @NotNull + @Override + protected Collection getNonExtensionsByName(JetScope scope, String name) { + VariableDescriptor variable = scope.getVariable(name); + if (variable != null && !variable.getReceiverParameter().exists()) { + return Collections.singleton(variable); + } + return Collections.emptyList(); + } + + @NotNull + @Override + protected Collection getMembersByName(@NotNull JetType receiverType, String name) { + VariableDescriptor variable = receiverType.getMemberScope().getVariable(name); + if (variable != null) { + return Collections.singleton(variable); + } + return Collections.emptyList(); + } + + @NotNull + @Override + protected Collection getExtensionsByName(JetScope scope, String name) { + VariableDescriptor variable = scope.getVariable(name); + if (variable != null && variable.getReceiverParameter().exists()) { + return Collections.singleton(variable); + } + return Collections.emptyList(); + } + }; +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java index 2429496de86..a7e7096b2de 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java @@ -5,6 +5,7 @@ import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.types.JetType; import java.util.Collection; import java.util.Set; @@ -15,17 +16,20 @@ import java.util.Set; /*package*/ interface TracingStrategy { TracingStrategy EMPTY = new TracingStrategy() { @Override - public void bindReference(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor receiver, @NotNull CallableDescriptor descriptor) {} + public void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCall resolvedCall) {} @Override public void unresolvedReference(@NotNull BindingTrace trace) {} @Override - public void recordAmbiguity(BindingTrace trace, Collection candidates) {} + public void recordAmbiguity(BindingTrace trace, Collection> candidates) {} @Override public void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor expectedReceiver) {} + @Override + public void wrongReceiverType(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor receiverParameter, @NotNull ReceiverDescriptor receiverArgument) {} + @Override public void noReceiverAllowed(@NotNull BindingTrace trace) {} @@ -36,37 +40,49 @@ import java.util.Set; public void wrongNumberOfTypeArguments(@NotNull BindingTrace trace, int expectedTypeArgumentCount) {} @Override - public void ambiguity(@NotNull BindingTrace trace, @NotNull Set descriptors) {} + public void ambiguity(@NotNull BindingTrace trace, @NotNull Set> descriptors) {} @Override - public void noneApplicable(@NotNull BindingTrace trace, @NotNull Set descriptors) {} + public void noneApplicable(@NotNull BindingTrace trace, @NotNull Set> descriptors) {} @Override public void instantiationOfAbstractClass(@NotNull BindingTrace trace) {} @Override public void typeInferenceFailed(@NotNull BindingTrace trace) {} + + @Override + public void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type) {} + + @Override + public void unnecessarySafeCall(@NotNull BindingTrace trace, @NotNull JetType type) {} }; - void bindReference(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor receiver, @NotNull CallableDescriptor descriptor); + void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCall resolvedCall); void unresolvedReference(@NotNull BindingTrace trace); - void recordAmbiguity(BindingTrace trace, Collection candidates); + void recordAmbiguity(BindingTrace trace, Collection> candidates); void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor expectedReceiver); + void wrongReceiverType(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor receiverParameter, @NotNull ReceiverDescriptor receiverArgument); + void noReceiverAllowed(@NotNull BindingTrace trace); void noValueForParameter(@NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter); void wrongNumberOfTypeArguments(@NotNull BindingTrace trace, int expectedTypeArgumentCount); - void ambiguity(@NotNull BindingTrace trace, @NotNull Set descriptors); + void ambiguity(@NotNull BindingTrace trace, @NotNull Set> descriptors); - void noneApplicable(@NotNull BindingTrace trace, @NotNull Set descriptors); + void noneApplicable(@NotNull BindingTrace trace, @NotNull Set> descriptors); void instantiationOfAbstractClass(@NotNull BindingTrace trace); void typeInferenceFailed(@NotNull BindingTrace trace); + + void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type); + + void unnecessarySafeCall(@NotNull BindingTrace trace, @NotNull JetType type); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java index a044f24d0da..9d0da1df69d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java @@ -6,7 +6,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lang.resolve.BindingTrace; +import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.CallMaker; import java.util.List; @@ -20,15 +21,17 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; * @author abreslav */ /*package*/ class ValueArgumentsToParametersMapper { - public static boolean mapValueArgumentsToParameters( - @NotNull ResolutionTask task, + public static boolean mapValueArgumentsToParameters( + @NotNull ResolutionTask task, @NotNull TracingStrategy tracing, - @NotNull Descriptor candidate, - @NotNull BindingTrace temporaryTrace, - @NotNull Map argumentsToParameters + @NotNull ResolvedCall candidateCall ) { + + TemporaryBindingTrace temporaryTrace = candidateCall.getTrace(); + Map varargs = Maps.newHashMap(); Set usedParameters = Sets.newHashSet(); + D candidate = candidateCall.getCandidateDescriptor(); List valueParameters = candidate.getValueParameters(); Map parameterByName = Maps.newHashMap(); @@ -36,7 +39,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; parameterByName.put(valueParameter.getName(), valueParameter); } - List valueArguments = task.getValueArguments(); + List valueArguments = task.getCall().getValueArguments(); boolean error = false; boolean someNamed = false; @@ -58,7 +61,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; temporaryTrace.report(ARGUMENT_PASSED_TWICE.on(nameReference)); } temporaryTrace.record(REFERENCE_TARGET, nameReference, valueParameterDescriptor); - argumentsToParameters.put(valueArgument, valueParameterDescriptor); + put(candidateCall, valueParameterDescriptor, valueArgument, varargs); } if (somePositioned) { // temporaryTrace.getErrorHandler().genericError(nameNode, "Mixing named and positioned arguments in not allowed"); @@ -78,12 +81,12 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; if (i < parameterCount) { ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(i); usedParameters.add(valueParameterDescriptor); - argumentsToParameters.put(valueArgument, valueParameterDescriptor); + put(candidateCall, valueParameterDescriptor, valueArgument, varargs); } else if (!valueParameters.isEmpty()) { ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1); if (valueParameterDescriptor.isVararg()) { - argumentsToParameters.put(valueArgument, valueParameterDescriptor); + put(candidateCall, valueParameterDescriptor, valueArgument, varargs); usedParameters.add(valueParameterDescriptor); } else { @@ -101,7 +104,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; } } - List functionLiteralArguments = task.getFunctionLiteralArguments(); + List functionLiteralArguments = task.getCall().getFunctionLiteralArguments(); if (!functionLiteralArguments.isEmpty()) { JetExpression possiblyLabeledFunctionLiteral = functionLiteralArguments.get(0); @@ -109,7 +112,8 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; // temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), getTooManyArgumentsMessage(candidate)); temporaryTrace.report(TOO_MANY_ARGUMENTS.on(possiblyLabeledFunctionLiteral, candidate)); error = true; - } else { + } + else { JetFunctionLiteralExpression functionLiteral; if (possiblyLabeledFunctionLiteral instanceof JetLabelQualifiedExpression) { JetLabelQualifiedExpression labeledFunctionLiteral = (JetLabelQualifiedExpression) possiblyLabeledFunctionLiteral; @@ -119,20 +123,20 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; functionLiteral = (JetFunctionLiteralExpression) possiblyLabeledFunctionLiteral; } - ValueParameterDescriptor parameterDescriptor = valueParameters.get(valueParameters.size() - 1); - if (parameterDescriptor.isVararg()) { + ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1); + if (valueParameterDescriptor.isVararg()) { // temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), "Passing value as a vararg is only allowed inside a parenthesized argument list"); temporaryTrace.report(VARARG_OUTSIDE_PARENTHESES.on(possiblyLabeledFunctionLiteral)); error = true; } else { - if (!usedParameters.add(parameterDescriptor)) { + if (!usedParameters.add(valueParameterDescriptor)) { // temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), getTooManyArgumentsMessage(candidate)); temporaryTrace.report(TOO_MANY_ARGUMENTS.on(possiblyLabeledFunctionLiteral, candidate)); error = true; } else { - argumentsToParameters.put(CallMaker.makeValueArgument(functionLiteral), parameterDescriptor); + put(candidateCall, valueParameterDescriptor, CallMaker.makeValueArgument(functionLiteral), varargs); } } } @@ -148,16 +152,52 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; for (ValueParameterDescriptor valueParameter : valueParameters) { if (!usedParameters.contains(valueParameter)) { - if (!valueParameter.hasDefaultValue() && !valueParameter.isVararg()) { -// tracing.reportWrongValueArguments(temporaryTrace, "No value passed for parameter " + valueParameter.getName()); + if (valueParameter.hasDefaultValue()) { + candidateCall.recordValueArgument(valueParameter, DefaultValueArgument.DEFAULT); + } + else if (valueParameter.isVararg()) { + candidateCall.recordValueArgument(valueParameter, new VarargValueArgument()); + } + else { + // tracing.reportWrongValueArguments(temporaryTrace, "No value passed for parameter " + valueParameter.getName()); tracing.noValueForParameter(temporaryTrace, valueParameter); error = true; } } } + + ReceiverDescriptor receiverParameter = candidate.getReceiverParameter(); + ReceiverDescriptor receiverArgument = candidateCall.getReceiverArgument(); + if (receiverParameter.exists() &&!receiverArgument.exists()) { + tracing.missingReceiver(temporaryTrace, receiverParameter); + error = true; + } + if (!receiverParameter.exists() && receiverArgument.exists()) { + tracing.noReceiverAllowed(temporaryTrace); + error = true; + } + + assert candidateCall.getThisObject().exists() == candidateCall.getResultingDescriptor().getExpectedThisObject().exists() : "Shouldn't happen because of TaskPrioritizer: " + candidateCall.getCandidateDescriptor(); + return error; } + private static void put(ResolvedCall candidateCall, ValueParameterDescriptor valueParameterDescriptor, ValueArgument valueArgument, Map varargs) { + if (valueParameterDescriptor.isVararg()) { + VarargValueArgument vararg = varargs.get(valueParameterDescriptor); + if (vararg == null) { + vararg = new VarargValueArgument(); + varargs.put(valueParameterDescriptor, vararg); + candidateCall.recordValueArgument(valueParameterDescriptor, vararg); + } + vararg.getArgumentExpressions().add(valueArgument.getArgumentExpression()); + } + else { + ResolvedValueArgument argument = new ExpressionValueArgument(valueArgument.getArgumentExpression()); + candidateCall.recordValueArgument(valueParameterDescriptor, argument); + } + } + // private static String getTooManyArgumentsMessage(Descriptor candidate) { // return "Too many arguments for " + DescriptorRenderer.TEXT.render(candidate); // } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/VarargValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/VarargValueArgument.java new file mode 100644 index 00000000000..3430aa4f8e5 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/VarargValueArgument.java @@ -0,0 +1,20 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import com.google.common.collect.Lists; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetExpression; + +import java.util.List; + +/** +* @author abreslav +*/ +public class VarargValueArgument implements ResolvedValueArgument { + private final List values = Lists.newArrayList(); + + @NotNull + @Override + public List getArgumentExpressions() { + return values; + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScope.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScope.java index f37b8ae6b16..04ea11c3be4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScope.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScope.java @@ -21,6 +21,8 @@ public interface WritableScope extends JetScope { void addClassifierAlias(@NotNull String name, @NotNull ClassifierDescriptor classifierDescriptor); + void addNamespaceAlias(@NotNull String name, @NotNull NamespaceDescriptor namespaceDescriptor); + void addNamespace(@NotNull NamespaceDescriptor namespaceDescriptor); @Nullable diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeImpl.java index b63ee731480..65e2693b630 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeImpl.java @@ -27,9 +27,13 @@ public class WritableScopeImpl extends WritableScopeWithImports { @Nullable private SetMultimap functionGroups; + @Nullable private Map variableClassOrNamespaceDescriptors; + @Nullable + private Map namespaceAliases; + @Nullable private Map> labelsToDescriptors; @@ -66,6 +70,12 @@ public class WritableScopeImpl extends WritableScopeWithImports { super.importClassifierAlias(importedClassifierName, classifierDescriptor); } + @Override + public void importNamespaceAlias(String aliasName, NamespaceDescriptor namespaceDescriptor) { + allDescriptors.add(namespaceDescriptor); + super.importNamespaceAlias(aliasName, namespaceDescriptor); + } + @NotNull @Override public Collection getAllDescriptors() { @@ -123,6 +133,14 @@ public class WritableScopeImpl extends WritableScopeWithImports { return variableClassOrNamespaceDescriptors; } + @NotNull + private Map getNamespaceAliases() { + if (namespaceAliases == null) { + namespaceAliases = Maps.newHashMap(); + } + return namespaceAliases; + } + @Override public void addVariableDescriptor(@NotNull VariableDescriptor variableDescriptor) { Map variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors(); @@ -189,13 +207,23 @@ public class WritableScopeImpl extends WritableScopeWithImports { @Override public void addClassifierAlias(@NotNull String name, @NotNull ClassifierDescriptor classifierDescriptor) { - Map variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors(); - DeclarationDescriptor originalDescriptor = variableClassOrNamespaceDescriptors.get(name); + checkForRedeclaration(name, classifierDescriptor); + getVariableClassOrNamespaceDescriptors().put(name, classifierDescriptor); + allDescriptors.add(classifierDescriptor); + } + + @Override + public void addNamespaceAlias(@NotNull String name, @NotNull NamespaceDescriptor namespaceDescriptor) { + checkForRedeclaration(name, namespaceDescriptor); + getNamespaceAliases().put(name, namespaceDescriptor); + allDescriptors.add(namespaceDescriptor); + } + + private void checkForRedeclaration(String name, DeclarationDescriptor classifierDescriptor) { + DeclarationDescriptor originalDescriptor = getVariableClassOrNamespaceDescriptors().get(name); if (originalDescriptor != null) { redeclarationHandler.handleRedeclaration(originalDescriptor, classifierDescriptor); } - variableClassOrNamespaceDescriptors.put(name, classifierDescriptor); - allDescriptors.add(classifierDescriptor); } @Override @@ -242,6 +270,9 @@ public class WritableScopeImpl extends WritableScopeWithImports { NamespaceDescriptor declaredNamespace = getDeclaredNamespace(name); if (declaredNamespace != null) return declaredNamespace; + NamespaceDescriptor aliased = getNamespaceAliases().get(name); + if (aliased != null) return aliased; + NamespaceDescriptor namespace = getWorkerScope().getNamespace(name); if (namespace != null) return namespace; return super.getNamespace(name); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeWithImports.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeWithImports.java index b88a8d17be3..e3205c0d9ee 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeWithImports.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeWithImports.java @@ -97,15 +97,24 @@ public abstract class WritableScopeWithImports extends JetScopeAdapter implement return null; } - public void importClassifierAlias(@NotNull String importedClassifierName, @NotNull ClassifierDescriptor classifierDescriptor) { + private WritableScope getCurrentIndividualImportScope() { if (currentIndividualImportScope == null) { WritableScopeImpl writableScope = new WritableScopeImpl(EMPTY, getContainingDeclaration(), RedeclarationHandler.DO_NOTHING).setDebugName("Individual import scope"); importScope(writableScope); currentIndividualImportScope = writableScope; } - currentIndividualImportScope.addClassifierAlias(importedClassifierName, classifierDescriptor); + return currentIndividualImportScope; } + public void importClassifierAlias(@NotNull String importedClassifierName, @NotNull ClassifierDescriptor classifierDescriptor) { + getCurrentIndividualImportScope().addClassifierAlias(importedClassifierName, classifierDescriptor); + } + + + public void importNamespaceAlias(String aliasName, NamespaceDescriptor namespaceDescriptor) { + getCurrentIndividualImportScope().addNamespaceAlias(aliasName, namespaceDescriptor); + } + @Override public String toString() { return getClass().getSimpleName() + "@" + Integer.toHexString(System.identityHashCode(this)) + " " + debugName + " for " + getContainingDeclaration(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WriteThroughScope.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WriteThroughScope.java index fb5e6e6a8b5..941562949e4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WriteThroughScope.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WriteThroughScope.java @@ -126,6 +126,11 @@ public class WriteThroughScope extends WritableScopeWithImports { writableWorker.addClassifierAlias(name, classifierDescriptor); } + @Override + public void addNamespaceAlias(@NotNull String name, @NotNull NamespaceDescriptor namespaceDescriptor) { + writableWorker.addNamespaceAlias(name, namespaceDescriptor); + } + @Override public void addNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) { writableWorker.addNamespace(namespaceDescriptor); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ClassReceiver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ClassReceiver.java index 85be4e2f593..ac1ac9c5b4a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ClassReceiver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ClassReceiver.java @@ -2,14 +2,28 @@ package org.jetbrains.jet.lang.resolve.scopes.receivers; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.types.JetType; /** * @author abreslav */ -public class ClassReceiver extends ImplicitReceiverDescriptor { +public class ClassReceiver implements ReceiverDescriptor { - public ClassReceiver(ClassDescriptor classDescriptor) { - super(classDescriptor, classDescriptor.getDefaultType()); + private final ClassDescriptor classDescriptor; + + public ClassReceiver(@NotNull ClassDescriptor classDescriptor) { + this.classDescriptor = classDescriptor; + } + + @Override + public boolean exists() { + return true; + } + + @NotNull + @Override + public JetType getType() { + return classDescriptor.getDefaultType(); } @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ReceiverDescriptorVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ReceiverDescriptorVisitor.java index f7ba43b15aa..1917e219255 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ReceiverDescriptorVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ReceiverDescriptorVisitor.java @@ -20,7 +20,7 @@ public class ReceiverDescriptorVisitor { return null; } - public R visitClassReceiver(ClassReceiver classReceiver, D data) { + public R visitClassReceiver(ClassReceiver receiver, D data) { return null; } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/CallMaker.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/CallMaker.java index 8da61d725d0..d7e23978a8f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/CallMaker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/CallMaker.java @@ -1,10 +1,12 @@ package org.jetbrains.jet.lang.types; import com.google.common.collect.Lists; +import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import java.util.Collections; import java.util.List; @@ -17,8 +19,8 @@ public class CallMaker { private static class ExpressionValueArgument implements ValueArgument { private final JetExpression expression; - private final PsiElement reportErrorsOn; + private final PsiElement reportErrorsOn; private ExpressionValueArgument(@NotNull JetExpression expression) { this(expression, expression); } @@ -60,18 +62,72 @@ public class CallMaker { } } - private static abstract class CallStub implements Call { + + private static class CallImpl implements Call { + + private final ASTNode callNode; + private final PsiElement callElement; + private final ReceiverDescriptor explicitReceiver; + private ASTNode callOperationNode; + private final JetExpression calleeExpression; + private final List valueArguments; + + protected CallImpl(@NotNull ASTNode callNode, @Nullable PsiElement callElement, @NotNull ReceiverDescriptor explicitReceiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression calleeExpression, @NotNull List valueArguments) { + this.callNode = callNode; + this.callElement = callElement; + this.explicitReceiver = explicitReceiver; + this.callOperationNode = callOperationNode; + this.calleeExpression = calleeExpression; + this.valueArguments = valueArguments; + } + + protected CallImpl(@NotNull PsiElement callElement, @NotNull ReceiverDescriptor explicitReceiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression calleeExpression, @NotNull List valueArguments) { + this(callElement.getNode(), callElement, explicitReceiver, callOperationNode, calleeExpression, valueArguments); + } + + @Override + public ASTNode getCallOperationNode() { + return callOperationNode; + } + + @NotNull + @Override + public ReceiverDescriptor getExplicitReceiver() { + return explicitReceiver; + } + + @Override + public JetExpression getCalleeExpression() { + return calleeExpression; + } + + @NotNull + @Override + public List getValueArguments() { + return valueArguments; + } + + @NotNull + @Override + public ASTNode getCallNode() { + return callNode; + } + + @Override + public PsiElement getCallElement() { + return callElement; + } @Override public JetValueArgumentList getValueArgumentList() { return null; } + @NotNull @Override public List getFunctionLiteralArguments() { return Collections.emptyList(); } - @NotNull @Override public List getTypeArguments() { @@ -83,42 +139,36 @@ public class CallMaker { return null; } - } - public static Call makeCallWithArguments(final JetExpression calleeExpression, final List valueArguments) { - return new CallStub() { - @Override - public JetExpression getCalleeExpression() { - return calleeExpression; - } - - @NotNull - @Override - public List getValueArguments() { - return valueArguments; - } - }; + @Override + public String toString() { + return getCallNode().getText(); + } } - public static Call makeCall(final JetExpression calleeExpression, final List argumentExpressions) { + public static Call makeCallWithExpressions(@NotNull JetElement callElement, @NotNull ReceiverDescriptor explicitReceiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression calleeExpression, @NotNull List argumentExpressions) { List arguments = Lists.newArrayList(); for (JetExpression argumentExpression : argumentExpressions) { arguments.add(makeValueArgument(argumentExpression, calleeExpression)); } - return makeCallWithArguments(calleeExpression, arguments); + return makeCall(callElement, explicitReceiver, callOperationNode, calleeExpression, arguments); } - public static Call makeCall(final JetBinaryExpression expression) { - return makeCall(expression.getOperationReference(), Collections.singletonList(expression.getRight())); + public static Call makeCall(JetElement callElement, ReceiverDescriptor explicitReceiver, @Nullable ASTNode callOperationNode, JetExpression calleeExpression, List arguments) { + return new CallImpl(callElement, explicitReceiver, callOperationNode, calleeExpression, arguments); } - public static Call makeCall(final JetUnaryExpression expression) { - return makeCallWithArguments(expression.getOperationSign(), Collections.emptyList()); + public static Call makeCall(@NotNull ReceiverDescriptor leftAsReceiver, JetBinaryExpression expression) { + return makeCallWithExpressions(expression, leftAsReceiver, null, expression.getOperationReference(), Collections.singletonList(expression.getRight())); } - public static Call makeCall(final JetArrayAccessExpression arrayAccessExpression, final JetExpression rightHandSide) { + public static Call makeCall(@NotNull ReceiverDescriptor baseAsReceiver, JetUnaryExpression expression) { + return makeCall(expression, baseAsReceiver, null, expression.getOperationSign(), Collections.emptyList()); + } + + public static Call makeCall(@NotNull ReceiverDescriptor arrayAsReceiver,JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide) { List arguments = Lists.newArrayList(arrayAccessExpression.getIndexExpressions()); arguments.add(rightHandSide); - return makeCall(arrayAccessExpression, arguments); + return makeCallWithExpressions(arrayAccessExpression, arrayAsReceiver, null, arrayAccessExpression, arguments); } public static ValueArgument makeValueArgument(@NotNull JetExpression expression) { @@ -129,7 +179,68 @@ public class CallMaker { return new ExpressionValueArgument(expression, reportErrorsOn); } - public static Call makePropertyCall(@NotNull JetSimpleNameExpression nameExpression) { - return makeCall(nameExpression, Collections.emptyList()); + public static Call makePropertyCall(@NotNull ReceiverDescriptor explicitReceiver, @Nullable ASTNode callOperationNode, @NotNull JetSimpleNameExpression nameExpression) { + return makeCallWithExpressions(nameExpression, explicitReceiver, callOperationNode, nameExpression, Collections.emptyList()); + } + + public static Call makeCall(@NotNull final ReceiverDescriptor explicitReceiver, @Nullable final ASTNode callOperationNode, @NotNull final JetCallElement callElement) { + return new Call() { + @Override + public ASTNode getCallOperationNode() { + return callOperationNode; + } + + @NotNull + @Override + public ReceiverDescriptor getExplicitReceiver() { + return explicitReceiver; + } + + @Nullable + public JetExpression getCalleeExpression() { + return callElement.getCalleeExpression(); + } + + @Nullable + public JetValueArgumentList getValueArgumentList() { + return callElement.getValueArgumentList(); + } + + @NotNull + public List getValueArguments() { + return callElement.getValueArguments(); + } + + @NotNull + public List getFunctionLiteralArguments() { + return callElement.getFunctionLiteralArguments(); + } + + @NotNull + public List getTypeArguments() { + return callElement.getTypeArguments(); + } + + @Nullable + public JetTypeArgumentList getTypeArgumentList() { + return callElement.getTypeArgumentList(); + } + + @NotNull + @Override + public ASTNode getCallNode() { + return callElement.getNode(); + } + + @Override + public PsiElement getCallElement() { + return callElement; + } + + @Override + public String toString() { + return callElement.toString(); + } + }; } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/DataFlowInfo.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/DataFlowInfo.java index 04ac9f08f6b..757aca4ad5f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/DataFlowInfo.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/DataFlowInfo.java @@ -4,6 +4,7 @@ import com.google.common.collect.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.VariableDescriptor; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.util.CommonSuppliers; import java.util.*; @@ -14,9 +15,9 @@ import java.util.*; public class DataFlowInfo { public static abstract class CompositionOperator { + public abstract DataFlowInfo compose(DataFlowInfo a, DataFlowInfo b); } - public static final CompositionOperator AND = new CompositionOperator() { @Override public DataFlowInfo compose(DataFlowInfo a, DataFlowInfo b) { @@ -31,7 +32,7 @@ public class DataFlowInfo { } }; - private static DataFlowInfo EMPTY = new DataFlowInfo(ImmutableMap.of(), Multimaps.newListMultimap(Collections.>emptyMap(), CommonSuppliers.getArrayListSupplier())); + private static DataFlowInfo EMPTY = new DataFlowInfo(ImmutableMap.of(), Multimaps.newListMultimap(Collections.>emptyMap(), CommonSuppliers.getArrayListSupplier())); public static DataFlowInfo getEmpty() { return EMPTY; @@ -39,10 +40,11 @@ public class DataFlowInfo { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - private final ImmutableMap nullabilityInfo; - private final ListMultimap typeInfo; + private final ImmutableMap nullabilityInfo; - private DataFlowInfo(ImmutableMap nullabilityInfo, ListMultimap typeInfo) { + private final ListMultimap typeInfo; + + private DataFlowInfo(ImmutableMap nullabilityInfo, ListMultimap typeInfo) { this.nullabilityInfo = nullabilityInfo; this.typeInfo = typeInfo; } @@ -60,13 +62,16 @@ public class DataFlowInfo { } @NotNull - public List getPossibleTypes(VariableDescriptor variableDescriptor) { - List types = typeInfo.get(variableDescriptor); - NullabilityFlags nullabilityFlags = nullabilityInfo.get(variableDescriptor); + private List getPossibleTypes(Object key, @NotNull JetType originalType) { + List types = typeInfo.get(key); + NullabilityFlags nullabilityFlags = nullabilityInfo.get(key); if (nullabilityFlags == null || nullabilityFlags.canBeNull()) { return types; } List enrichedTypes = Lists.newArrayListWithCapacity(types.size()); + if (originalType.isNullable()) { + enrichedTypes.add(TypeUtils.makeNotNullable(originalType)); + } for (JetType type: types) { if (type.isNullable()) { enrichedTypes.add(TypeUtils.makeNotNullable(type)); @@ -78,21 +83,30 @@ public class DataFlowInfo { return enrichedTypes; } + @NotNull + public List getPossibleTypesForVariable(@NotNull VariableDescriptor variableDescriptor) { + return getPossibleTypes(variableDescriptor, variableDescriptor.getOutType()); + } + + public List getPossibleTypesForReceiver(@NotNull ReceiverDescriptor receiver) { + return getPossibleTypes(receiver, receiver.getType()); + } + public DataFlowInfo equalsToNull(@NotNull VariableDescriptor variableDescriptor, boolean notNull) { return new DataFlowInfo(getEqualsToNullMap(variableDescriptor, notNull), typeInfo); } - private ImmutableMap getEqualsToNullMap(VariableDescriptor variableDescriptor, boolean notNull) { - Map builder = Maps.newHashMap(nullabilityInfo); + private ImmutableMap getEqualsToNullMap(VariableDescriptor variableDescriptor, boolean notNull) { + Map builder = Maps.newHashMap(nullabilityInfo); NullabilityFlags nullabilityFlags = nullabilityInfo.get(variableDescriptor); boolean varNotNull = notNull || (nullabilityFlags != null && !nullabilityFlags.canBeNull); builder.put(variableDescriptor, new NullabilityFlags(!varNotNull, varNotNull)); return ImmutableMap.copyOf(builder); } - private ImmutableMap getEqualsToNullMap(VariableDescriptor[] variableDescriptors, boolean notNull) { + private ImmutableMap getEqualsToNullMap(VariableDescriptor[] variableDescriptors, boolean notNull) { if (variableDescriptors.length == 0) return nullabilityInfo; - Map builder = Maps.newHashMap(nullabilityInfo); + Map builder = Maps.newHashMap(nullabilityInfo); for (VariableDescriptor variableDescriptor : variableDescriptors) { if (variableDescriptor != null) { NullabilityFlags nullabilityFlags = nullabilityInfo.get(variableDescriptor); @@ -104,14 +118,14 @@ public class DataFlowInfo { } public DataFlowInfo isInstanceOf(@NotNull VariableDescriptor variableDescriptor, @NotNull JetType type) { - ListMultimap newTypeInfo = copyTypeInfo(); + ListMultimap newTypeInfo = copyTypeInfo(); newTypeInfo.put(variableDescriptor, type); return new DataFlowInfo(getEqualsToNullMap(variableDescriptor, !type.isNullable()), newTypeInfo); } public DataFlowInfo isInstanceOf(@NotNull VariableDescriptor[] variableDescriptors, @NotNull JetType type) { if (variableDescriptors.length == 0) return this; - ListMultimap newTypeInfo = copyTypeInfo(); + ListMultimap newTypeInfo = copyTypeInfo(); for (VariableDescriptor variableDescriptor : variableDescriptors) { if (variableDescriptor != null) { newTypeInfo.put(variableDescriptor, type); @@ -121,59 +135,63 @@ public class DataFlowInfo { } public DataFlowInfo and(DataFlowInfo other) { - Map nullabilityMapBuilder = Maps.newHashMap(); + Map nullabilityMapBuilder = Maps.newHashMap(); nullabilityMapBuilder.putAll(nullabilityInfo); - for (Map.Entry entry : other.nullabilityInfo.entrySet()) { - VariableDescriptor variableDescriptor = entry.getKey(); + for (Map.Entry entry : other.nullabilityInfo.entrySet()) { + Object key = entry.getKey(); NullabilityFlags otherFlags = entry.getValue(); - NullabilityFlags thisFlags = nullabilityInfo.get(variableDescriptor); + NullabilityFlags thisFlags = nullabilityInfo.get(key); if (thisFlags != null) { - nullabilityMapBuilder.put(variableDescriptor, thisFlags.and(otherFlags)); + nullabilityMapBuilder.put(key, thisFlags.and(otherFlags)); } else { - nullabilityMapBuilder.put(variableDescriptor, otherFlags); + nullabilityMapBuilder.put(key, otherFlags); } } - ListMultimap newTypeInfo = copyTypeInfo(); + ListMultimap newTypeInfo = copyTypeInfo(); newTypeInfo.putAll(other.typeInfo); return new DataFlowInfo(ImmutableMap.copyOf(nullabilityMapBuilder), newTypeInfo); } - private ListMultimap copyTypeInfo() { - ListMultimap newTypeInfo = Multimaps.newListMultimap(Maps.>newHashMap(), CommonSuppliers.getArrayListSupplier()); + private ListMultimap copyTypeInfo() { + ListMultimap newTypeInfo = Multimaps.newListMultimap(Maps.>newHashMap(), CommonSuppliers.getArrayListSupplier()); newTypeInfo.putAll(typeInfo); return newTypeInfo; } public DataFlowInfo or(DataFlowInfo other) { - Map builder = Maps.newHashMap(nullabilityInfo); + Map builder = Maps.newHashMap(nullabilityInfo); builder.keySet().retainAll(other.nullabilityInfo.keySet()); - for (Map.Entry entry : builder.entrySet()) { - VariableDescriptor variableDescriptor = entry.getKey(); + for (Map.Entry entry : builder.entrySet()) { + Object key = entry.getKey(); NullabilityFlags thisFlags = entry.getValue(); - NullabilityFlags otherFlags = other.nullabilityInfo.get(variableDescriptor); + NullabilityFlags otherFlags = other.nullabilityInfo.get(key); assert (otherFlags != null); - builder.put(variableDescriptor, thisFlags.or(otherFlags)); + builder.put(key, thisFlags.or(otherFlags)); } - ListMultimap newTypeInfo = Multimaps.newListMultimap(Maps.>newHashMap(), CommonSuppliers.getArrayListSupplier()); + ListMultimap newTypeInfo = Multimaps.newListMultimap(Maps.>newHashMap(), CommonSuppliers.getArrayListSupplier()); - Set keys = newTypeInfo.keySet(); + Set keys = newTypeInfo.keySet(); keys.retainAll(other.typeInfo.keySet()); - for (VariableDescriptor variableDescriptor : keys) { - Collection thisTypes = typeInfo.get(variableDescriptor); - Collection otherTypes = other.typeInfo.get(variableDescriptor); + for (Object key : keys) { + Collection thisTypes = typeInfo.get(key); + Collection otherTypes = other.typeInfo.get(key); Collection newTypes = Sets.newHashSet(thisTypes); newTypes.retainAll(otherTypes); - newTypeInfo.putAll(variableDescriptor, newTypes); + newTypeInfo.putAll(key, newTypes); } return new DataFlowInfo(ImmutableMap.copyOf(builder), newTypeInfo); } + + public DataFlowInfo nullabilityOnly() { + return new DataFlowInfo(nullabilityInfo, EMPTY.copyTypeInfo()); + } private static class NullabilityFlags { private final boolean canBeNull; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java index 6e5761683d0..394d310c7c1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java @@ -105,6 +105,7 @@ public class ErrorUtils { Visibility.INTERNAL, true, null, + ReceiverDescriptor.NO_RECEIVER, "", ERROR_PROPERTY_TYPE, ERROR_PROPERTY_TYPE); @@ -112,6 +113,7 @@ public class ErrorUtils { FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl(ERROR_CLASS, Collections.emptyList(), ""); return functionDescriptor.initialize( null, + ReceiverDescriptor.NO_RECEIVER, typeParameters, getValueParameters(functionDescriptor, positionedValueArgumentTypes), createErrorType(""), @@ -123,6 +125,7 @@ public class ErrorUtils { public static FunctionDescriptor createErrorFunction(int typeParameterCount, List positionedValueParameterTypes) { return new FunctionDescriptorImpl(ERROR_CLASS, Collections.emptyList(), "").initialize( null, + ReceiverDescriptor.NO_RECEIVER, Collections.emptyList(), // TODO Collections.emptyList(), // TODO createErrorType(""), diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java index 2036d25cafb..6029d19c358 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java @@ -312,8 +312,7 @@ public class JetStandardLibrary { @NotNull public JetType getArrayType(@NotNull JetType argument) { - Variance variance = Variance.INVARIANT; - return getArrayType(variance, argument); + return getArrayType(Variance.INVARIANT, argument); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index bc1770da090..5e3eaa10af6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -12,15 +12,15 @@ 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; import org.jetbrains.jet.lang.diagnostics.DiagnosticWithPsiElement; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.*; +import org.jetbrains.jet.lang.resolve.calls.AutoCastUtils; import org.jetbrains.jet.lang.resolve.calls.CallResolver; -import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResult; +import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults; import org.jetbrains.jet.lang.resolve.constants.*; import org.jetbrains.jet.lang.resolve.constants.StringValue; import org.jetbrains.jet.lang.resolve.scopes.JetScope; @@ -36,14 +36,14 @@ import java.util.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.resolve.BindingContext.*; +import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER; /** * @author abreslav */ public class JetTypeInferrer { - private static final Set numberConversions = new HashSet(); - + private static final Set numberConversions = Sets.newHashSet(); static { numberConversions.add("dbl"); numberConversions.add("flt"); @@ -158,40 +158,52 @@ public class JetTypeInferrer { .put(JetTokens.PLUSEQ, JetTokens.PLUS) .put(JetTokens.MINUSEQ, JetTokens.MINUS) .build(); + + @Nullable + public static String getNameForOperationSymbol(@NotNull IElementType token) { + String name = unaryOperationNames.get(token); + if (name != null) return name; + name = binaryOperationNames.get(token); + if (name != null) return name; + name = assignmentOperationNames.get(token); + if (name != null) return name; + if (comparisonOperations.contains(token)) return "compareTo"; + if (equalsOperations.contains(token)) return "equals"; + if (inOperations.contains(token)) return "contains"; + return null; + } private final JetSemanticServices semanticServices; - private final JetFlowInformationProvider flowInformationProvider; - private final CallResolver callResolver; +// 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.callResolver = new CallResolver(semanticServices, this); +// this.flowInformationProvider = flowInformationProvider; } public Services getServices(@NotNull BindingTrace trace) { return new Services(trace); } - public CallResolver getCallResolver() { - return callResolver; - } - public class Services { private final BindingTrace trace; private final CompileTimeConstantResolver compileTimeConstantResolver; private final TypeInferrerVisitor typeInferrerVisitor; private final TypeInferrerVisitorWithNamespaces typeInferrerVisitorWithNamespaces; + private final CallResolver callResolver; private Services(BindingTrace trace) { this.trace = trace; this.compileTimeConstantResolver = new CompileTimeConstantResolver(semanticServices, trace); this.typeInferrerVisitor = new TypeInferrerVisitor(); this.typeInferrerVisitorWithNamespaces = new TypeInferrerVisitorWithNamespaces(); + this.callResolver = new CallResolver(semanticServices, JetTypeInferrer.this, DataFlowInfo.getEmpty()); } public TypeInferrerVisitorWithWritableScope newTypeInferrerVisitorWithWritableScope(WritableScope scope) { @@ -220,33 +232,33 @@ public class JetTypeInferrer { return callResolver; } - //TODO JetElement -> JetWhenConditionCall || JetQualifiedExpression - private void checkNullSafety(@Nullable JetType receiverType, @NotNull ASTNode operationTokenNode, @Nullable FunctionDescriptor callee, @NotNull JetElement element) { - if (receiverType != null && callee != null) { - boolean namespaceType = receiverType instanceof NamespaceType; - boolean nullableReceiver = !namespaceType && receiverType.isNullable(); - ReceiverDescriptor calleeReceiver = callee.getReceiver(); - boolean calleeForbidsNullableReceiver = !calleeReceiver.exists() || !calleeReceiver.getType().isNullable(); - - IElementType operationSign = operationTokenNode.getElementType(); - if (nullableReceiver && calleeForbidsNullableReceiver && operationSign == JetTokens.DOT) { -// trace.getErrorHandler().genericError(operationTokenNode, "Only safe calls (?.) are allowed on a nullable receiver of type " + receiverType); - trace.report(UNSAFE_CALL.on(operationTokenNode, receiverType)); - } - else if ((!nullableReceiver || !calleeForbidsNullableReceiver) && operationSign == JetTokens.SAFE_ACCESS) { - if (namespaceType) { -// trace.getErrorHandler().genericError(operationTokenNode, "Safe calls are not allowed on namespaces"); - trace.report(SAFE_CALLS_ARE_NOT_ALLOWED_ON_NAMESPACES.on(operationTokenNode)); - } - else { -// trace.getErrorHandler().genericWarning(operationTokenNode, "Unnecessary safe call on a non-null receiver of type " + receiverType); - - trace.report(UNNECESSARY_SAFE_CALL.on(element, operationTokenNode, receiverType)); - - } - } - } - } +// TODO JetElement -> JetWhenConditionCall || JetQualifiedExpression +// private void checkNullSafety(@Nullable JetType receiverType, @NotNull ASTNode operationTokenNode, @Nullable FunctionDescriptor callee, @NotNull JetElement element) { +// if (receiverType != null && callee != null) { +// boolean namespaceType = receiverType instanceof NamespaceType; +// boolean nullableReceiver = !namespaceType && receiverType.isNullable(); +// ReceiverDescriptor calleeReceiver = callee.getReceiverParameter(); +// boolean calleeForbidsNullableReceiver = !calleeReceiver.exists() || !calleeReceiver.getType().isNullable(); +// +// IElementType operationSign = operationTokenNode.getElementType(); +// if (nullableReceiver && calleeForbidsNullableReceiver && operationSign == JetTokens.DOT) { +//// trace.getErrorHandler().genericError(operationTokenNode, "Only safe calls (?.) are allowed on a nullable receiver of type " + receiverType); +// trace.report(UNSAFE_CALL.on(operationTokenNode, receiverType)); +// } +// else if ((!nullableReceiver || !calleeForbidsNullableReceiver) && operationSign == JetTokens.SAFE_ACCESS) { +// if (namespaceType) { +//// trace.getErrorHandler().genericError(operationTokenNode, "Safe calls are not allowed on namespaces"); +// trace.report(SAFE_CALLS_ARE_NOT_ALLOWED_ON_NAMESPACES.on(operationTokenNode)); +// } +// else { +//// trace.getErrorHandler().genericWarning(operationTokenNode, "Unnecessary safe call on a non-null receiver of type " + receiverType); +// +// trace.report(UNNECESSARY_SAFE_CALL.on(element, operationTokenNode, receiverType)); +// +// } +// } +// } +// } public void checkFunctionReturnType(@NotNull JetScope outerScope, @NotNull JetDeclarationWithBody function, @NotNull FunctionDescriptor functionDescriptor) { checkFunctionReturnType(outerScope, function, functionDescriptor, DataFlowInfo.getEmpty()); @@ -258,7 +270,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 @@ -292,13 +304,13 @@ 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; + if (bodyExpression == null) return; final boolean blockBody = function.hasBlockBody(); final TypeInferenceContext context = @@ -314,56 +326,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 @@ -380,26 +398,52 @@ 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( - @NotNull BindingTrace trace, + private Map collectReturnedExpressionsWithTypes( + final @NotNull BindingTrace trace, JetScope outerScope, - JetDeclarationWithBody function, + final JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) { JetExpression bodyExpression = function.getBodyExpression(); 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()) { + //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, JetDeclarationWithBody outerFunction) { + 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; + } + + @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); + } + Map typeMap = new HashMap(); for (JetExpression returnedExpression : returnedExpressions) { JetType cachedType = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, returnedExpression); trace.record(STATEMENT, returnedExpression, false); @@ -407,9 +451,6 @@ public class JetTypeInferrer { typeMap.put(returnedExpression, cachedType); } } - for (JetElement jetElement : elementsReturningUnit) { - typeMap.put(jetElement, JetStandardClasses.getUnitType()); - } return typeMap; } @@ -427,35 +468,57 @@ 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 { @@ -487,67 +550,67 @@ public class JetTypeInferrer { }; } - //TODO - private JetType enrichOutType(JetExpression expression, JetType initialType, @NotNull TypeInferenceContext context) { - if (expression == null) return initialType; - VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(expression, context); - if (variableDescriptor != null) { - return context.dataFlowInfo.getOutType(variableDescriptor); - } - return initialType; - } +// //TODO +// private JetType enrichOutType(JetExpression expression, JetType initialType, @NotNull TypeInferenceContext context) { +// if (expression == null) return initialType; +// VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(expression, context); +// if (variableDescriptor != null) { +// return context.dataFlowInfo.getOutType(variableDescriptor); +// } +// return initialType; +// } + +// @Nullable +// private JetType checkType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull TypeInferenceContext context) { +// if (expressionType != null && context.expectedType != null && context.expectedType != NO_EXPECTED_TYPE) { +// if (!semanticServices.getTypeChecker().isSubtypeOf(expressionType, context.expectedType)) { +// context.trace.report(TYPE_MISMATCH.on(expression, context.expectedType, expressionType)); +// } +// } +// return expressionType; +// } @Nullable private JetType checkType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull TypeInferenceContext context) { - if (expressionType != null && context.expectedType != null && context.expectedType != NO_EXPECTED_TYPE) { - if (!semanticServices.getTypeChecker().isSubtypeOf(expressionType, context.expectedType)) { - context.trace.report(TYPE_MISMATCH.on(expression, context.expectedType, expressionType)); - } - } - return expressionType; - } - - @Nullable - private JetType checkEnrichedType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull TypeInferenceContext context) { if (expressionType == null || context.expectedType == null || context.expectedType == NO_EXPECTED_TYPE || semanticServices.getTypeChecker().isSubtypeOf(expressionType, context.expectedType)) { return expressionType; } - VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(expression, context); - boolean appropriateTypeFound = false; - if (variableDescriptor != null) { - List possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypes(variableDescriptor)); - Collections.reverse(possibleTypes); - for (JetType possibleType : possibleTypes) { - if (semanticServices.getTypeChecker().isSubtypeOf(possibleType, context.expectedType)) { - appropriateTypeFound = true; - break; - } - } - if (!appropriateTypeFound) { - JetType notnullType = context.dataFlowInfo.getOutType(variableDescriptor); - if (notnullType != null && semanticServices.getTypeChecker().isSubtypeOf(notnullType, context.expectedType)) { - appropriateTypeFound = true; - } - } - } - if (!appropriateTypeFound) { +// VariableDescriptor variableDescriptor = AutoCastUtils.getVariableDescriptorFromSimpleName(context.trace.getBindingContext(), expression); +// boolean appropriateTypeFound = false; +// if (variableDescriptor != null) { +// List possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)); +// Collections.reverse(possibleTypes); +// for (JetType possibleType : possibleTypes) { +// if (semanticServices.getTypeChecker().isSubtypeOf(possibleType, context.expectedType)) { +// appropriateTypeFound = true; +// break; +// } +// } +// if (!appropriateTypeFound) { +// JetType notnullType = context.dataFlowInfo.getOutType(variableDescriptor); +// if (notnullType != null && semanticServices.getTypeChecker().isSubtypeOf(notnullType, context.expectedType)) { +// appropriateTypeFound = true; +// } +// } +// } + if (AutoCastUtils.castExpression(expression, context.expectedType, context.dataFlowInfo, context.trace) == null) { // context.trace.getErrorHandler().typeMismatch(expression, context.expectedType, expressionType); context.trace.report(TYPE_MISMATCH.on(expression, context.expectedType, expressionType)); return expressionType; } - checkAutoCast(expression, context.expectedType, variableDescriptor, context.trace); +// checkAutoCast(expression, context.expectedType, variableDescriptor, context.trace); return context.expectedType; } - private void checkAutoCast(JetExpression expression, JetType type, VariableDescriptor variableDescriptor, BindingTrace trace) { - if (variableDescriptor.isVar()) { -// trace.getErrorHandler().genericError(expression.getNode(), "Automatic cast to " + type + " is impossible, because variable " + variableDescriptor.getName() + " is mutable"); - trace.report(AUTOCAST_IMPOSSIBLE.on(expression, type, variableDescriptor)); - } else { - trace.record(BindingContext.AUTOCAST, expression, type); - } - } +// private void checkAutoCast(JetExpression expression, JetType type, VariableDescriptor variableDescriptor, BindingTrace trace) { +// if (variableDescriptor.isVar()) { +//// trace.getErrorHandler().genericError(expression.getNode(), "Automatic cast to " + type + " is impossible, because variable " + variableDescriptor.getName() + " is mutable"); +// trace.report(AUTOCAST_IMPOSSIBLE.on(expression, type, variableDescriptor)); +// } else { +// trace.record(BindingContext.AUTOCAST, expression, type); +// } +// } @NotNull private List checkArgumentTypes(@NotNull List argumentTypes, @NotNull List arguments, @NotNull List expectedArgumentTypes, @NotNull TypeInferenceContext context) { @@ -556,7 +619,7 @@ public class JetTypeInferrer { } List result = Lists.newArrayListWithCapacity(arguments.size()); for (int i = 0, argumentTypesSize = argumentTypes.size(); i < argumentTypesSize; i++) { - result.add(checkEnrichedType(argumentTypes.get(i), arguments.get(i), context.replaceExpectedType(expectedArgumentTypes.get(i).getType()))); + result.add(checkType(argumentTypes.get(i), arguments.get(i), context.replaceExpectedType(expectedArgumentTypes.get(i).getType()))); } return result; } @@ -612,6 +675,9 @@ public class JetTypeInferrer { public final JetType expectedType; public final JetType expectedReturnType; + @Deprecated // Use a getter + private CallResolver callResolver; + @Deprecated // Only factory methods private TypeInferenceContext( @NotNull BindingTrace trace, @@ -666,10 +732,38 @@ public class JetTypeInferrer { if (expectedType == newExpectedType && expectedReturnType == newExpectedReturnType) return this; return newContext(trace, scope, dataFlowInfo, newExpectedType, newExpectedReturnType); } + + public CallResolver getCallResolver() { + if (callResolver == null) { + callResolver = new CallResolver(semanticServices, JetTypeInferrer.this, this.dataFlowInfo); + } + return callResolver; + } + + @Nullable + public FunctionDescriptor resolveCallWithGivenName(@NotNull Call call, @NotNull JetReferenceExpression functionReference, @NotNull String name, @NotNull ReceiverDescriptor receiver) { + return getCallResolver().resolveCallWithGivenName(trace, scope, call, functionReference, name, expectedType); + } + + @Nullable + public JetType resolveCall(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetCallExpression callExpression) { + return getCallResolver().resolveCall(trace, scope, CallMaker.makeCall(receiver, callOperationNode, callExpression), expectedType); + } + + @Nullable + public VariableDescriptor resolveSimpleProperty(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetSimpleNameExpression nameExpression) { + Call call = CallMaker.makePropertyCall(receiver, callOperationNode, nameExpression); + return getCallResolver().resolveSimpleProperty(trace, scope, call, expectedType); + } + + @NotNull + public OverloadResolutionResults resolveExactSignature(@NotNull ReceiverDescriptor receiver, @NotNull String name, @NotNull List parameterTypes) { + return getCallResolver().resolveExactSignature(scope, receiver, name, parameterTypes); + } + } private class TypeInferrerVisitor extends JetVisitor { - protected DataFlowInfo resultDataFlowInfo; @Nullable @@ -718,10 +812,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 @@ -749,16 +844,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())); +// } +// } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -775,11 +870,11 @@ public class JetTypeInferrer { } else { context.trace.record(REFERENCE_TARGET, expression, property); - return context.services.checkEnrichedType(property.getOutType(), expression, context); + return context.services.checkType(property.getOutType(), expression, context); } } else { - return getSelectorReturnType(ReceiverDescriptor.NO_RECEIVER, expression, context); // TODO : Extensions to this + return getSelectorReturnType(NO_RECEIVER, null, expression, context); // TODO : Extensions to this // assert JetTokens.IDENTIFIER == expression.getReferencedNameElementType(); // if (referencedName != null) { // VariableDescriptor variable = context.scope.getVariable(referencedName); @@ -789,7 +884,7 @@ public class JetTypeInferrer { // if (result == null) { // context.trace.getErrorHandler().genericError(expression.getNode(), "This variable is not readable in this context"); // } -// return context.services.checkEnrichedType(result, expression, context); +// return context.services.checkType(result, expression, context); // } // else { // return lookupNamespaceOrClassObject(expression, referencedName, context); @@ -804,12 +899,12 @@ public class JetTypeInferrer { // context.trace.getErrorHandler().genericError(expression.getNode(), "Classifier " + classifier.getName() + " does not have a class object"); // } // context.trace.record(REFERENCE_TARGET, expression, classifier); -// return context.services.checkEnrichedType(result, expression, context); +// return context.services.checkType(result, expression, context); // } // else { // JetType[] result = new JetType[1]; // if (furtherNameLookup(expression, referencedName, result, context)) { -// return context.services.checkEnrichedType(result[0], expression, context); +// return context.services.checkType(result[0], expression, context); // } // // } @@ -825,27 +920,35 @@ public class JetTypeInferrer { if (classifier != null) { JetType classObjectType = classifier.getClassObjectType(); JetType result = null; - if (classObjectType != null && (isNamespacePosition() || classifier.isClassObjectAValue())) { - result = classObjectType; - } - else { -// context.trace.getErrorHandler().genericError(expression.getNode(), "Classifier " + classifier.getName() + " does not have a class object"); - context.trace.report(NO_CLASS_OBJECT.on(expression, classifier)); + if (classObjectType != null) { + if (isNamespacePosition() || classifier.isClassObjectAValue()) { + result = classObjectType; + } + else { + // context.trace.getErrorHandler().genericError(expression.getNode(), "Classifier " + classifier.getName() + " does not have a class object"); + context.trace.report(NO_CLASS_OBJECT.on(expression, classifier)); + } + context.trace.record(REFERENCE_TARGET, expression, classifier); + if (result == null) { + return ErrorUtils.createErrorType("No class object in " + expression.getReferencedName()); + } + return context.services.checkType(result, expression, context); } + } + JetType[] result = new JetType[1]; + TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace); + if (furtherNameLookup(expression, referencedName, result, context.replaceBindingTrace(temporaryTrace))) { + temporaryTrace.commit(); + return context.services.checkType(result[0], expression, context); + } + // To report NO_CLASS_OBJECT when no namespace found + if (classifier != null) { + context.trace.report(NO_CLASS_OBJECT.on(expression, classifier)); context.trace.record(REFERENCE_TARGET, expression, classifier); - if (result == null) { - return ErrorUtils.createErrorType("No class object in " + expression.getReferencedName()); - } - return context.services.checkEnrichedType(result, expression, context); + return ErrorUtils.createErrorType("No class object in " + expression.getReferencedName()); } - else { - JetType[] result = new JetType[1]; - if (furtherNameLookup(expression, referencedName, result, context)) { - return context.services.checkEnrichedType(result[0], expression, context); - } - - } - return null; + temporaryTrace.commit(); + return result[0]; } public boolean isNamespacePosition() { @@ -857,7 +960,7 @@ public class JetTypeInferrer { if (namespaceType != null) { // context.trace.getErrorHandler().genericError(expression.getNode(), "Expression expected, but a namespace name found"); context.trace.report(EXPRESSION_EXPECTED_NAMESPACE_FOUND.on(expression)); - return true; + result[0] = ErrorUtils.createErrorType("Type for " + referencedName); } return false; } @@ -972,7 +1075,7 @@ public class JetTypeInferrer { else { effectiveReceiverType = receiverType; } - functionDescriptor.initialize(effectiveReceiverType, Collections.emptyList(), valueParameterDescriptors, null, Modality.FINAL, Visibility.LOCAL); + functionDescriptor.initialize(effectiveReceiverType, NO_RECEIVER, Collections.emptyList(), valueParameterDescriptors, null, Modality.FINAL, Visibility.LOCAL); context.trace.record(BindingContext.FUNCTION, expression, functionDescriptor); JetType returnType = NO_EXPECTED_TYPE; @@ -980,7 +1083,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) { @@ -994,6 +1097,7 @@ public class JetTypeInferrer { if (functionTypeExpected) { JetType expectedReturnType = JetStandardClasses.getReturnType(expectedType); if (JetStandardClasses.isUnit(expectedReturnType)) { + functionDescriptor.setReturnType(expectedReturnType); return context.services.checkType(JetStandardClasses.getFunctionType(Collections.emptyList(), effectiveReceiverType, parameterTypes, expectedReturnType), expression, context); } @@ -1089,6 +1193,7 @@ public class JetTypeInferrer { @Override public JetType visitReturnExpression(JetReturnExpression expression, TypeInferenceContext 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)); @@ -1111,11 +1216,13 @@ public class JetTypeInferrer { @Override public JetType visitBreakExpression(JetBreakExpression expression, TypeInferenceContext context) { + labelsResolver.recordLabel(expression, context); return context.services.checkType(JetStandardClasses.getNothingType(), expression, context); } @Override public JetType visitContinueExpression(JetContinueExpression expression, TypeInferenceContext context) { + labelsResolver.recordLabel(expression, context); return context.services.checkType(JetStandardClasses.getNothingType(), expression, context); } @@ -1235,50 +1342,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) { - // 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); - 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(); @@ -1411,9 +1475,9 @@ public class JetTypeInferrer { if (callSuffixExpression != null) { // JetType selectorReturnType = getType(compositeScope, callSuffixExpression, false, context); assert subjectExpression != null; - JetType selectorReturnType = getSelectorReturnType(new ExpressionReceiver(subjectExpression, subjectType), callSuffixExpression, context);//getType(compositeScope, callSuffixExpression, false, context); + JetType selectorReturnType = getSelectorReturnType(new ExpressionReceiver(subjectExpression, subjectType), condition.getOperationTokenNode(), callSuffixExpression, context);//getType(compositeScope, callSuffixExpression, false, context); ensureBooleanResultWithCustomSubject(callSuffixExpression, selectorReturnType, "This expression", context); - context.services.checkNullSafety(subjectType, condition.getOperationTokenNode(), getCalleeFunctionDescriptor(callSuffixExpression, context), condition); +// context.services.checkNullSafety(subjectType, condition.getOperationTokenNode(), getCalleeFunctionDescriptor(callSuffixExpression, context), condition); } } @@ -1422,7 +1486,7 @@ public class JetTypeInferrer { JetExpression rangeExpression = condition.getRangeExpression(); if (rangeExpression != null) { assert subjectExpression != null; - checkInExpression(condition.getOperationReference(), subjectExpression, rangeExpression, context); + checkInExpression(condition, condition.getOperationReference(), subjectExpression, rangeExpression, context); } } @@ -1490,7 +1554,7 @@ public class JetTypeInferrer { JetExpression decomposerExpression = pattern.getDecomposerExpression(); if (decomposerExpression != null) { ReceiverDescriptor receiver = new TransientReceiver(subjectType); - JetType selectorReturnType = getSelectorReturnType(receiver, decomposerExpression, context); + JetType selectorReturnType = getSelectorReturnType(receiver, null, decomposerExpression, context); result[0] = checkPatternType(pattern.getArgumentList(), selectorReturnType == null ? ErrorUtils.createErrorType("No type") : selectorReturnType, scopeToExtend, context); } @@ -1810,12 +1874,36 @@ public class JetTypeInferrer { DataFlowInfo conditionInfo = condition == null ? context.dataFlowInfo : extractDataFlowInfoFromCondition(condition, true, scopeToExtend, context); getTypeWithNewScopeAndDataFlowInfo(scopeToExtend, body, conditionInfo, context); } - if (!flowInformationProvider.isBreakable(expression)) { + if (!containsBreak(expression, context)) { // resultScope = newWritableScopeImpl(); resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false, null, context); } return context.services.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType); } + + private boolean containsBreak(final JetLoopExpression loopExpression, final TypeInferenceContext context) { + final boolean[] result = new boolean[1]; + result[0] = false; + //todo breaks in inline function literals + loopExpression.visit(new JetTreeVisitor() { + @Override + 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; + } + + @Override + public Void visitLoopExpression(JetLoopExpression loopExpression, JetLoopExpression outerLoop) { + return super.visitLoopExpression(loopExpression, loopExpression); + } + }, loopExpression); + + return result[0]; + } @Override public JetType visitDoWhileExpression(JetDoWhileExpression expression, TypeInferenceContext contextWithExpectedType) { @@ -1840,7 +1928,7 @@ public class JetTypeInferrer { } JetExpression condition = expression.getCondition(); checkCondition(conditionScope, condition, context); - if (!flowInformationProvider.isBreakable(expression)) { + if (!containsBreak(expression, context)) { // resultScope = newWritableScopeImpl(); resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false, null, context); } @@ -1899,9 +1987,9 @@ public class JetTypeInferrer { @Nullable private JetType checkIterableConvention(@NotNull ExpressionReceiver loopRange, TypeInferenceContext context) { JetExpression loopRangeExpression = loopRange.getExpression(); - OverloadResolutionResult iteratorResolutionResult = callResolver.resolveExactSignature(context.scope, loopRange, "iterator", Collections.emptyList()); - if (iteratorResolutionResult.isSuccess()) { - FunctionDescriptor iteratorFunction = iteratorResolutionResult.getDescriptor(); + OverloadResolutionResults iteratorResolutionResults = context.resolveExactSignature(loopRange, "iterator", Collections.emptyList()); + if (iteratorResolutionResults.isSuccess()) { + FunctionDescriptor iteratorFunction = iteratorResolutionResults.getResult().getResultingDescriptor(); context.trace.record(LOOP_RANGE_ITERATOR, loopRangeExpression, iteratorFunction); @@ -1923,27 +2011,27 @@ public class JetTypeInferrer { context.trace.record(LOOP_RANGE_HAS_NEXT, loopRange.getExpression(), hasNextFunctionSupported ? hasNextFunction : hasNextProperty); } - OverloadResolutionResult nextResolutionResult = callResolver.resolveExactSignature(context.scope, new TransientReceiver(iteratorType), "next", Collections.emptyList()); - if (nextResolutionResult.isAmbiguity()) { + OverloadResolutionResults nextResolutionResults = context.resolveExactSignature(new TransientReceiver(iteratorType), "next", Collections.emptyList()); + if (nextResolutionResults.isAmbiguity()) { // context.trace.getErrorHandler().genericError(reportErrorsOn, "Method 'iterator().next()' is ambiguous for this expression"); context.trace.report(NEXT_AMBIGUITY.on(loopRangeExpression)); - } else if (nextResolutionResult.isNothing()) { + } else if (nextResolutionResults.isNothing()) { // context.trace.getErrorHandler().genericError(reportErrorsOn, "Loop range must have an 'iterator().next()' method"); context.trace.report(NEXT_MISSING.on(loopRangeExpression)); } else { - FunctionDescriptor nextFunction = nextResolutionResult.getDescriptor(); + FunctionDescriptor nextFunction = nextResolutionResults.getResult().getResultingDescriptor(); context.trace.record(LOOP_RANGE_NEXT, loopRange.getExpression(), nextFunction); return nextFunction.getReturnType(); } } else { - if (iteratorResolutionResult.isAmbiguity()) { + if (iteratorResolutionResults.isAmbiguity()) { // StringBuffer stringBuffer = new StringBuffer("Method 'iterator()' is ambiguous for this expression: "); -// for (FunctionDescriptor functionDescriptor : iteratorResolutionResult.getDescriptors()) { +// for (FunctionDescriptor functionDescriptor : iteratorResolutionResults.getResults()) { // stringBuffer.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append(" "); // } // errorMessage = stringBuffer.toString(); - context.trace.report(ITERATOR_AMBIGUITY.on(loopRangeExpression, iteratorResolutionResult.getDescriptors())); + context.trace.report(ITERATOR_AMBIGUITY.on(loopRangeExpression, iteratorResolutionResults.getResults())); } else { // context.trace.getErrorHandler().genericError(reportErrorsOn, errorMessage); @@ -1955,21 +2043,21 @@ public class JetTypeInferrer { @Nullable private FunctionDescriptor checkHasNextFunctionSupport(@NotNull JetExpression loopRange, @NotNull JetType iteratorType, TypeInferenceContext context) { - OverloadResolutionResult hasNextResolutionResult = callResolver.resolveExactSignature(context.scope, new TransientReceiver(iteratorType), "hasNext", Collections.emptyList()); - if (hasNextResolutionResult.isAmbiguity()) { + OverloadResolutionResults hasNextResolutionResults = context.resolveExactSignature(new TransientReceiver(iteratorType), "hasNext", Collections.emptyList()); + if (hasNextResolutionResults.isAmbiguity()) { // context.trace.getErrorHandler().genericError(loopRange.getNode(), "Method 'iterator().hasNext()' is ambiguous for this expression"); context.trace.report(HAS_NEXT_FUNCTION_AMBIGUITY.on(loopRange)); - } else if (hasNextResolutionResult.isNothing()) { + } else if (hasNextResolutionResults.isNothing()) { return null; } else { - assert hasNextResolutionResult.isSuccess(); - JetType hasNextReturnType = hasNextResolutionResult.getDescriptor().getReturnType(); + assert hasNextResolutionResults.isSuccess(); + JetType hasNextReturnType = hasNextResolutionResults.getResult().getResultingDescriptor().getReturnType(); if (!isBoolean(hasNextReturnType)) { // context.trace.getErrorHandler().genericError(loopRange.getNode(), "The 'iterator().hasNext()' method of the loop range must return Boolean, but returns " + hasNextReturnType); context.trace.report(HAS_NEXT_FUNCTION_TYPE_MISMATCH.on(loopRange, hasNextReturnType)); } } - return hasNextResolutionResult.getDescriptor(); + return hasNextResolutionResults.getResult().getResultingDescriptor(); } @Nullable @@ -2015,9 +2103,9 @@ public class JetTypeInferrer { } // Clean resolution: no autocasts - TemporaryBindingTrace cleanResolutionTrace = TemporaryBindingTrace.create(context.trace); - TypeInferenceContext cleanResolutionContext = context.replaceBindingTrace(cleanResolutionTrace); - JetType selectorReturnType = getSelectorReturnType(new ExpressionReceiver(receiverExpression, receiverType), selectorExpression, cleanResolutionContext); +// TemporaryBindingTrace cleanResolutionTrace = TemporaryBindingTrace.create(context.trace); +// TypeInferenceContext cleanResolutionContext = context.replaceBindingTrace(cleanResolutionTrace); + JetType selectorReturnType = getSelectorReturnType(new ExpressionReceiver(receiverExpression, receiverType), expression.getOperationTokenNode(), selectorExpression, context); //TODO move further if (expression.getOperationSign() == JetTokens.SAFE_ACCESS) { @@ -2025,40 +2113,40 @@ public class JetTypeInferrer { selectorReturnType = TypeUtils.makeNullable(selectorReturnType); } } - if (selectorReturnType != null) { - cleanResolutionTrace.addAllMyDataTo(context.trace); - } - else { - VariableDescriptor variableDescriptor = cleanResolutionContext.services.getVariableDescriptorFromSimpleName(receiverExpression, context); - boolean somethingFound = false; - if (variableDescriptor != null) { - List possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypes(variableDescriptor)); - Collections.reverse(possibleTypes); - - TemporaryBindingTrace autocastResolutionTrace = TemporaryBindingTrace.create(context.trace); - TypeInferenceContext autocastResolutionContext = context.replaceBindingTrace(autocastResolutionTrace); - for (JetType possibleType : possibleTypes) { - selectorReturnType = getSelectorReturnType(new ExpressionReceiver(receiverExpression, possibleType), selectorExpression, autocastResolutionContext); - if (selectorReturnType != null) { - context.services.checkAutoCast(receiverExpression, possibleType, variableDescriptor, autocastResolutionTrace); - autocastResolutionTrace.commit(); - somethingFound = true; - break; - } - else { - autocastResolutionTrace = TemporaryBindingTrace.create(context.trace); - autocastResolutionContext = context.replaceBindingTrace(autocastResolutionTrace); - } - } - } - if (!somethingFound) { - cleanResolutionTrace.commit(); - } - } +// if (selectorReturnType != null) { +// cleanResolutionTrace.addAllMyDataTo(context.trace); +// } +// else { +// VariableDescriptor variableDescriptor = cleanResolutionContext.services.getVariableDescriptorFromSimpleName(receiverExpression, context); +// boolean somethingFound = false; +// if (variableDescriptor != null) { +// List possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)); +// Collections.reverse(possibleTypes); +// +// TemporaryBindingTrace autocastResolutionTrace = TemporaryBindingTrace.create(context.trace); +// TypeInferenceContext autocastResolutionContext = context.replaceBindingTrace(autocastResolutionTrace); +// for (JetType possibleType : possibleTypes) { +// selectorReturnType = getSelectorReturnType(new ExpressionReceiver(receiverExpression, possibleType), selectorExpression, autocastResolutionContext); +// if (selectorReturnType != null) { +// context.services.checkAutoCast(receiverExpression, possibleType, variableDescriptor, autocastResolutionTrace); +// autocastResolutionTrace.commit(); +// somethingFound = true; +// break; +// } +// else { +// autocastResolutionTrace = TemporaryBindingTrace.create(context.trace); +// autocastResolutionContext = context.replaceBindingTrace(autocastResolutionTrace); +// } +// } +// } +// if (!somethingFound) { +// cleanResolutionTrace.commit(); +// } +// } JetType result; if (expression.getOperationSign() == JetTokens.QUEST) { - if (selectorReturnType != null && !isBoolean(selectorReturnType) && selectorExpression != null) { + if (selectorReturnType != null && !isBoolean(selectorReturnType)) { // TODO : more comprehensible error message // context.trace.getErrorHandler().typeMismatch(selectorExpression, semanticServices.getStandardLibrary().getBooleanType(), selectorReturnType); context.trace.report(TYPE_MISMATCH.on(selectorExpression, semanticServices.getStandardLibrary().getBooleanType(), selectorReturnType)); @@ -2068,16 +2156,15 @@ public class JetTypeInferrer { else { result = selectorReturnType; } - if (selectorExpression != null && result != null) { + // TODO : this is suspicious: remove this code? + if (result != null) { context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, result); } if (selectorReturnType != null) { - // TODO : extensions to 'Any?' - if (selectorExpression != null) { - receiverType = context.services.enrichOutType(receiverExpression, receiverType, context); - - context.services.checkNullSafety(receiverType, expression.getOperationTokenNode(), getCalleeFunctionDescriptor(selectorExpression, context), expression); - } +// // TODO : extensions to 'Any?' +// receiverType = context.services.enrichOutType(receiverExpression, receiverType, context); +// +// context.services.checkNullSafety(receiverType, expression.getOperationTokenNode(), getCalleeFunctionDescriptor(selectorExpression, context), expression); } return context.services.checkType(result, expression, contextWithExpectedType); } @@ -2112,84 +2199,84 @@ public class JetTypeInferrer { } } - - @NotNull - private FunctionDescriptor getCalleeFunctionDescriptor(@NotNull JetExpression selectorExpression, final TypeInferenceContext context) { - final FunctionDescriptor[] result = new FunctionDescriptor[1]; - selectorExpression.accept(new JetVisitorVoid() { - @Override - public void visitCallExpression(JetCallExpression callExpression) { - JetExpression calleeExpression = callExpression.getCalleeExpression(); - if (calleeExpression != null) { - calleeExpression.accept(this); - } - } - - @Override - public void visitReferenceExpression(JetReferenceExpression referenceExpression) { - DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(REFERENCE_TARGET, referenceExpression); - if (declarationDescriptor instanceof FunctionDescriptor) { - result[0] = (FunctionDescriptor) declarationDescriptor; - } - } - - @Override - public void visitArrayAccessExpression(JetArrayAccessExpression expression) { - expression.getArrayExpression().accept(this); - } - - @Override - public void visitBinaryExpression(JetBinaryExpression expression) { - expression.getLeft().accept(this); - } - - @Override - public void visitQualifiedExpression(JetQualifiedExpression expression) { - expression.getReceiverExpression().accept(this); - } - - @Override - public void visitJetElement(JetElement element) { -// context.trace.getErrorHandler().genericError(element.getNode(), "Unsupported [getCalleeFunctionDescriptor]: " + element); - context.trace.report(UNSUPPORTED.on(element, "getCalleeFunctionDescriptor")); - } - }); - if (result[0] == null) { - result[0] = ErrorUtils.createErrorFunction(0, Collections.emptyList()); - } - return result[0]; - } +// @NotNull +// private FunctionDescriptor getCalleeFunctionDescriptor(@NotNull JetExpression selectorExpression, final TypeInferenceContext context) { +// final FunctionDescriptor[] result = new FunctionDescriptor[1]; +// selectorExpression.accept(new JetVisitorVoid() { +// @Override +// public void visitCallExpression(JetCallExpression callExpression) { +// JetExpression calleeExpression = callExpression.getCalleeExpression(); +// if (calleeExpression != null) { +// calleeExpression.accept(this); +// } +// } +// +// @Override +// public void visitReferenceExpression(JetReferenceExpression referenceExpression) { +// DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(REFERENCE_TARGET, referenceExpression); +// if (declarationDescriptor instanceof FunctionDescriptor) { +// result[0] = (FunctionDescriptor) declarationDescriptor; +// } +// } +// +// @Override +// public void visitArrayAccessExpression(JetArrayAccessExpression expression) { +// expression.getArrayExpression().accept(this); +// } +// +// @Override +// public void visitBinaryExpression(JetBinaryExpression expression) { +// expression.getLeft().accept(this); +// } +// +// @Override +// public void visitQualifiedExpression(JetQualifiedExpression expression) { +// expression.getReceiverExpression().accept(this); +// } +// +// @Override +// public void visitJetElement(JetElement element) { +//// context.trace.getErrorHandler().genericError(element.getNode(), "Unsupported [getCalleeFunctionDescriptor]: " + element); +// context.trace.report(UNSUPPORTED.on(element, "getCalleeFunctionDescriptor")); +// } +// }); +// if (result[0] == null) { +// result[0] = ErrorUtils.createErrorFunction(0, Collections.emptyList()); +// } +// return result[0]; +// } @Nullable - private JetType getSelectorReturnType(@NotNull ReceiverDescriptor receiver, @NotNull JetExpression selectorExpression, @NotNull TypeInferenceContext context) { + private JetType getSelectorReturnType(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression selectorExpression, @NotNull TypeInferenceContext context) { if (selectorExpression instanceof JetCallExpression) { - return callResolver.resolveCall(context.trace, context.scope, receiver, (JetCallExpression) selectorExpression, context.expectedType); + JetCallExpression callExpression = (JetCallExpression) selectorExpression; + return context.resolveCall(receiver, callOperationNode, callExpression); } else if (selectorExpression instanceof JetSimpleNameExpression) { JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) selectorExpression; TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace); - VariableDescriptor variableDescriptor = callResolver.resolveSimpleProperty(temporaryTrace, context.scope, receiver, nameExpression, context.expectedType); + VariableDescriptor variableDescriptor = context.replaceBindingTrace(temporaryTrace).resolveSimpleProperty(receiver, callOperationNode, nameExpression); if (variableDescriptor != null) { temporaryTrace.commit(); - return context.services.checkEnrichedType(variableDescriptor.getOutType(), nameExpression, context); + return context.services.checkType(variableDescriptor.getOutType(), nameExpression, context); } TypeInferenceContext newContext = receiver.exists() ? context.replaceScope(receiver.getType().getMemberScope()) : context; JetType jetType = lookupNamespaceOrClassObject(nameExpression, nameExpression.getReferencedName(), newContext); if (jetType == null) { context.trace.report(UNRESOLVED_REFERENCE.on(nameExpression)); } - return context.services.checkEnrichedType(jetType, nameExpression, context); + return context.services.checkType(jetType, nameExpression, context); // JetScope scope = receiverType != null ? receiverType.getMemberScope() : context.scope; // return getType(selectorExpression, context.replaceScope(scope)); } else if (selectorExpression instanceof JetQualifiedExpression) { JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) selectorExpression; JetExpression newReceiverExpression = qualifiedExpression.getReceiverExpression(); - JetType newReceiverType = getSelectorReturnType(receiver, newReceiverExpression, context.replaceExpectedType(NO_EXPECTED_TYPE)); + JetType newReceiverType = getSelectorReturnType(receiver, callOperationNode, newReceiverExpression, context.replaceExpectedType(NO_EXPECTED_TYPE)); JetExpression newSelectorExpression = qualifiedExpression.getSelectorExpression(); if (newReceiverType != null && newSelectorExpression != null) { - return getSelectorReturnType(new ExpressionReceiver(newReceiverExpression, newReceiverType), newSelectorExpression, context); + return getSelectorReturnType(new ExpressionReceiver(newReceiverExpression, newReceiverType), qualifiedExpression.getOperationTokenNode(), newSelectorExpression, context); } } else { @@ -2202,7 +2289,7 @@ public class JetTypeInferrer { @Override public JetType visitCallExpression(JetCallExpression expression, TypeInferenceContext context) { - JetType expressionType = callResolver.resolveCall(context.trace, context.scope, ReceiverDescriptor.NO_RECEIVER, expression, context.expectedType); + JetType expressionType = context.resolveCall(NO_RECEIVER, null, expression); return context.services.checkType(expressionType, expression, context); } @@ -2226,8 +2313,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); @@ -2239,14 +2331,11 @@ public class JetTypeInferrer { ExpressionReceiver receiver = getExpressionReceiver(baseExpression, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceScope(context.scope)); if (receiver == null) return null; - FunctionDescriptor functionDescriptor = callResolver.resolveCallWithGivenName( - context.trace, - context.scope, - CallMaker.makeCall(expression), + FunctionDescriptor functionDescriptor = context.resolveCallWithGivenName( + CallMaker.makeCall(receiver, expression), expression.getOperationSign(), name, - receiver, - context.expectedType); + receiver); if (functionDescriptor == null) return null; JetType returnType = functionDescriptor.getReturnType(); @@ -2271,6 +2360,7 @@ public class JetTypeInferrer { else { result = returnType; } + return context.services.checkType(result, expression, context); } @@ -2294,10 +2384,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); @@ -2317,24 +2407,24 @@ public class JetTypeInferrer { String name = "equals"; if (right != null) { ExpressionReceiver receiver = safeGetExpressionReceiver(left, context.replaceScope(context.scope)); - OverloadResolutionResult resolutionResult = callResolver.resolveExactSignature( - context.scope, receiver, "equals", + OverloadResolutionResults resolutionResults = context.resolveExactSignature( + receiver, "equals", Collections.singletonList(JetStandardClasses.getNullableAnyType())); - if (resolutionResult.isSuccess()) { - FunctionDescriptor equals = resolutionResult.getDescriptor(); + if (resolutionResults.isSuccess()) { + FunctionDescriptor equals = resolutionResults.getResult().getResultingDescriptor(); context.trace.record(REFERENCE_TARGET, operationSign, equals); if (ensureBooleanResult(operationSign, name, equals.getReturnType(), context)) { ensureNonemptyIntersectionOfOperandTypes(expression, context); } } else { - if (resolutionResult.isAmbiguity()) { + if (resolutionResults.isAmbiguity()) { // StringBuilder stringBuilder = new StringBuilder(); -// for (FunctionDescriptor functionDescriptor : resolutionResult.getDescriptors()) { +// for (FunctionDescriptor functionDescriptor : resolutionResults.getResults()) { // stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append(" "); // } // context.trace.getErrorHandler().genericError(operationSign.getNode(), "Ambiguous function: " + stringBuilder); - context.trace.report(OVERLOAD_RESOLUTION_AMBIGUITY.on(operationSign, resolutionResult.getDescriptors())); + context.trace.report(OVERLOAD_RESOLUTION_AMBIGUITY.on(operationSign, resolutionResults.getResults())); } else { // context.trace.getErrorHandler().genericError(operationSign.getNode(), "No method 'equals(Any?) : Boolean' available"); @@ -2355,7 +2445,7 @@ public class JetTypeInferrer { result = ErrorUtils.createErrorType("No right argument"); // TODO return null; } - checkInExpression(operationSign, left, right, context); + checkInExpression(expression, expression.getOperationReference(), expression.getLeft(), expression.getRight(), context); result = semanticServices.getStandardLibrary().getBooleanType(); } else if (operationType == JetTokens.ANDAND || operationType == JetTokens.OROR) { @@ -2395,15 +2485,13 @@ public class JetTypeInferrer { return context.services.checkType(result, expression, contextWithExpectedType); } - private void checkInExpression(JetSimpleNameExpression operationSign, JetExpression left, JetExpression right, TypeInferenceContext context) { + private void checkInExpression(JetElement callElement, @NotNull JetSimpleNameExpression operationSign, @NotNull JetExpression left, @NotNull JetExpression right, TypeInferenceContext context) { String name = "contains"; ExpressionReceiver receiver = safeGetExpressionReceiver(right, context.replaceExpectedType(NO_EXPECTED_TYPE)); - FunctionDescriptor functionDescriptor = callResolver.resolveCallWithGivenName( - context.trace, - context.scope, - CallMaker.makeCall(operationSign, Collections.singletonList(left)), + FunctionDescriptor functionDescriptor = context.resolveCallWithGivenName( + CallMaker.makeCallWithExpressions(callElement, receiver, null, operationSign, Collections.singletonList(left)), operationSign, - name, receiver, context.expectedType); + name, receiver); JetType containsType = functionDescriptor != null ? functionDescriptor.getReturnType() : null; ensureBooleanResult(operationSign, name, containsType, context); } @@ -2469,14 +2557,11 @@ public class JetTypeInferrer { ExpressionReceiver receiver = getExpressionReceiver(arrayExpression, context.replaceScope(context.scope)); if (receiver != null) { - FunctionDescriptor functionDescriptor = callResolver.resolveCallWithGivenName( - context.trace, - context.scope, - CallMaker.makeCall(expression, expression.getIndexExpressions()), - expression, + FunctionDescriptor functionDescriptor = context.resolveCallWithGivenName( + CallMaker.makeCallWithExpressions(expression, receiver, null, expression, expression.getIndexExpressions()), + expression, "get", - receiver, - context.expectedType); + receiver); if (functionDescriptor != null) { return context.services.checkType(functionDescriptor.getReturnType(), expression, contextWithExpectedType); } @@ -2487,27 +2572,24 @@ public class JetTypeInferrer { @Nullable protected JetType getTypeForBinaryCall(JetScope scope, String name, TypeInferenceContext context, JetBinaryExpression binaryExpression) { ExpressionReceiver receiver = safeGetExpressionReceiver(binaryExpression.getLeft(), context.replaceScope(scope)); - FunctionDescriptor functionDescriptor = callResolver.resolveCallWithGivenName( - context.trace, - scope, - CallMaker.makeCall(binaryExpression), + FunctionDescriptor functionDescriptor = context.replaceScope(scope).resolveCallWithGivenName( + CallMaker.makeCall(receiver, binaryExpression), binaryExpression.getOperationReference(), name, - receiver, - context.expectedType); + receiver); if (functionDescriptor != null) { - if (receiver.getType().isNullable()) { - // TODO : better error message for '1 + nullableVar' case - JetExpression right = binaryExpression.getRight(); - String rightText = right == null ? "" : right.getText(); - String leftText = binaryExpression.getLeft().getText(); -// context.trace.getErrorHandler().genericError(binaryExpression.getOperationReference().getNode(), -// "Infix call corresponds to a dot-qualified call '" + -// leftText + "." + name + "(" + rightText + ")'" + -// " which is not allowed on a nullable receiver '" + leftText + "'." + -// " Use '?.'-qualified call instead"); - context.trace.report(UNSAFE_INFIX_CALL.on(binaryExpression.getOperationReference(), leftText, name, rightText)); - } +// if (receiver.getType().isNullable()) { +// // TODO : better error message for '1 + nullableVar' case +// JetExpression right = binaryExpression.getRight(); +// String rightText = right == null ? "" : right.getText(); +// String leftText = binaryExpression.getLeft().getText(); +//// context.trace.getErrorHandler().genericError(binaryExpression.getOperationReference().getNode(), +//// "Infix call corresponds to a dot-qualified call '" + +//// leftText + "." + name + "(" + rightText + ")'" + +//// " which is not allowed on a nullable receiver '" + leftText + "'." + +//// " Use '?.'-qualified call instead"); +// context.trace.report(UNSAFE_INFIX_CALL.on(binaryExpression.getOperationReference(), leftText, name, rightText)); +// } return functionDescriptor.getReturnType(); @@ -2619,7 +2701,7 @@ public class JetTypeInferrer { PropertyDescriptor propertyDescriptor = context.classDescriptorResolver.resolveObjectDeclarationAsPropertyDescriptor(scope.getContainingDeclaration(), declaration, classDescriptor); scope.addVariableDescriptor(propertyDescriptor); } - return null; + return checkExpectedType(declaration, context); } @Override @@ -2655,7 +2737,7 @@ public class JetTypeInferrer { } scope.addVariableDescriptor(propertyDescriptor); - return null; + return checkExpectedType(property, context); } @Override @@ -2663,7 +2745,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 @@ -2678,7 +2760,7 @@ public class JetTypeInferrer { @Override public JetType visitDeclaration(JetDeclaration dcl, TypeInferenceContext context) { - return visitJetElement(dcl, context); + return checkExpectedType(dcl, context); } @Override @@ -2700,6 +2782,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; } @@ -2722,41 +2815,51 @@ public class JetTypeInferrer { // } } if (left instanceof JetSimpleNameExpression) { - JetSimpleNameExpression variable = (JetSimpleNameExpression) left; - String referencedName = variable.getReferencedName(); - if (variable.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER + JetSimpleNameExpression simpleName = (JetSimpleNameExpression) left; + String referencedName = simpleName.getReferencedName(); + if (simpleName.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER && referencedName != null) { PropertyDescriptor property = context.scope.getPropertyByFieldReference(referencedName); if (property != null) { - context.trace.record(BindingContext.VARIABLE_ASSIGNMENT, variable, property); + context.trace.record(BindingContext.VARIABLE_ASSIGNMENT, simpleName, property); + } + } + VariableDescriptor variable = AutoCastUtils.getVariableDescriptorFromSimpleName(context.trace.getBindingContext(), simpleName); + if (variable != null) { + DeclarationDescriptor containingDeclaration = variable.getContainingDeclaration(); + if (context.scope.getContainingDeclaration() != containingDeclaration && containingDeclaration instanceof CallableDescriptor) { + context.trace.record(MUST_BE_WRAPPED_IN_A_REF, variable); } } } - return null; + return checkExpectedType(expression, context); } private JetType resolveArrayAccessToLValue(JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide, JetSimpleNameExpression operationSign, TypeInferenceContext context) { ExpressionReceiver receiver = getExpressionReceiver(arrayAccessExpression.getArrayExpression(), context.replaceScope(scope)); if (receiver == null) return null; // - Call call = CallMaker.makeCall(arrayAccessExpression, rightHandSide); + Call call = CallMaker.makeCall(receiver, arrayAccessExpression, rightHandSide); // // TODO : nasty hack: effort is duplicated // callResolver.resolveCallWithGivenName( // scope, // call, // arrayAccessExpression, // "set", arrayAccessExpression.getArrayExpression(), NO_EXPECTED_TYPE); - FunctionDescriptor functionDescriptor = callResolver.resolveCallWithGivenName( - context.trace, - scope, + FunctionDescriptor functionDescriptor = context.replaceScope(scope).replaceExpectedType(NO_EXPECTED_TYPE).resolveCallWithGivenName( call, arrayAccessExpression, - "set", receiver, NO_EXPECTED_TYPE); + "set", receiver); if (functionDescriptor == null) return null; context.trace.record(REFERENCE_TARGET, operationSign, functionDescriptor); 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")); @@ -2764,4 +2867,135 @@ public class JetTypeInferrer { return null; } } + + private class LabelsResolver { + private final Map> labeledElements = new HashMap>(); + + public 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); + } + } + + public void exitLabeledElement(@NotNull 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 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 FunctionDescriptor || declarationDescriptor instanceof ClassDescriptor) { + element = (JetElement) context.trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, declarationDescriptor); + } + else { + throw new UnsupportedOperationException(); // TODO + } + 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) { + context.trace.report(UNRESOLVED_REFERENCE.on(labelExpression)); + } + return null; + } + 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); + return result; + } + + 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.getReceiverParameter(); + } + 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).getReceiverParameter(); + 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/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); diff --git a/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java b/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java index 4e3542c197e..2a52a1d3f54 100644 --- a/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java +++ b/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java @@ -186,7 +186,7 @@ public class DescriptorRenderer implements Renderer { renderModality(descriptor.getModality(), builder); String typeString = renderPropertyPrefixAndComputeTypeString( builder, descriptor.getTypeParameters(), - descriptor.getReceiver(), + descriptor.getReceiverParameter(), descriptor.getOutType(), descriptor.getInType()); renderName(descriptor, builder); @@ -215,7 +215,7 @@ public class DescriptorRenderer implements Renderer { builder.append(renderKeyword("fun")).append(" "); renderTypeParameters(descriptor.getTypeParameters(), builder); - ReceiverDescriptor receiver = descriptor.getReceiver(); + ReceiverDescriptor receiver = descriptor.getReceiverParameter(); if (receiver.exists()) { builder.append(escape(renderType(receiver.getType()))).append("."); } diff --git a/docs/CSClub_Kotlin.key b/docs/CSClub_Kotlin.key new file mode 100644 index 00000000000..becd3eb0037 Binary files /dev/null and b/docs/CSClub_Kotlin.key differ diff --git a/idea/src/org/jetbrains/jet/plugin/JetHighlighter.java b/idea/src/org/jetbrains/jet/plugin/JetHighlighter.java index 79903d2774b..215a4a63f8a 100644 --- a/idea/src/org/jetbrains/jet/plugin/JetHighlighter.java +++ b/idea/src/org/jetbrains/jet/plugin/JetHighlighter.java @@ -97,6 +97,15 @@ public class JetHighlighter extends SyntaxHighlighterBase { JET_AUTO_CAST_EXPRESSION = TextAttributesKey.createTextAttributesKey("JET.AUTO.CAST.EXPRESSION", clone); } + public static final TextAttributesKey JET_WRAPPED_INTO_REF; + + static { + TextAttributes attributes = new TextAttributes(); + attributes.setEffectType(EffectType.LINE_UNDERSCORE); + attributes.setEffectColor(Color.BLACK); + JET_WRAPPED_INTO_REF = TextAttributesKey.createTextAttributesKey("JET.WRAPPED.INTO.REF", attributes); + } + public static final TextAttributesKey JET_AUTOCREATED_IT; static { diff --git a/idea/src/org/jetbrains/jet/plugin/annotations/DebugInfoAnnotator.java b/idea/src/org/jetbrains/jet/plugin/annotations/DebugInfoAnnotator.java index 3b82898afe8..f0d8b73d0c8 100644 --- a/idea/src/org/jetbrains/jet/plugin/annotations/DebugInfoAnnotator.java +++ b/idea/src/org/jetbrains/jet/plugin/annotations/DebugInfoAnnotator.java @@ -15,6 +15,7 @@ import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.diagnostics.UnresolvedReferenceDiagnostic; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.types.ErrorUtils; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.plugin.AnalyzerFacade; @@ -91,7 +92,7 @@ public class DebugInfoAnnotator implements Annotator { target = labelTarget.getText(); } else { - Collection declarationDescriptors = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, expression); + Collection> declarationDescriptors = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, expression); if (declarationDescriptors != null) { target = "[" + declarationDescriptors.size() + " descriptors]"; } diff --git a/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java b/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java index a845fd21838..85c004ef2de 100644 --- a/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java +++ b/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java @@ -3,6 +3,7 @@ package org.jetbrains.jet.plugin.annotations; import com.google.common.collect.Sets; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInspection.ProblemHighlightType; +import com.intellij.lang.ASTNode; import com.intellij.lang.annotation.Annotation; import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.Annotator; @@ -117,9 +118,28 @@ public class JetPsiChecker implements Annotator { holder.createInfoAnnotation(expression, "Automatically declared based on the expected type").setTextAttributes(JetHighlighter.JET_AUTOCREATED_IT); } } + + markVariableAsWrappedIfNeeded(expression.getNode(), target); super.visitSimpleNameExpression(expression); } + private void markVariableAsWrappedIfNeeded(ASTNode node, DeclarationDescriptor target) { + if (target instanceof VariableDescriptor) { + VariableDescriptor variableDescriptor = (VariableDescriptor) target; + if (bindingContext.get(MUST_BE_WRAPPED_IN_A_REF, variableDescriptor)) { + holder.createInfoAnnotation(node, "Wrapped into a ref-object to be modifier when captured in a closure").setTextAttributes(JetHighlighter.JET_WRAPPED_INTO_REF); + } + + } + } + + @Override + public void visitProperty(JetProperty property) { + DeclarationDescriptor declarationDescriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, property); + markVariableAsWrappedIfNeeded(property.getNameIdentifier().getNode(), declarationDescriptor); + super.visitProperty(property); + } + @Override public void visitExpression(JetExpression expression) { JetType autoCast = bindingContext.get(AUTOCAST, expression); diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/AddFunctionBodyFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/AddFunctionBodyFix.java index 7131d3b0e02..4c919f86e94 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/AddFunctionBodyFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/AddFunctionBodyFix.java @@ -12,8 +12,8 @@ import org.jetbrains.jet.lang.psi.*; /** * @author svtk */ -public class AddFunctionBodyFix extends JetIntentionAction { - public AddFunctionBodyFix(@NotNull JetFunctionOrPropertyAccessor element) { +public class AddFunctionBodyFix extends JetIntentionAction { + public AddFunctionBodyFix(@NotNull JetFunction element) { super(element); } @@ -37,7 +37,7 @@ public class AddFunctionBodyFix extends JetIntentionAction createFactory() { - return new JetIntentionActionFactory() { + public static JetIntentionActionFactory createFactory() { + return new JetIntentionActionFactory() { @Override - public JetIntentionAction createAction(DiagnosticWithPsiElement diagnostic) { - assert diagnostic.getPsiElement() instanceof JetFunctionOrPropertyAccessor; - return new AddFunctionBodyFix((JetFunctionOrPropertyAccessor) diagnostic.getPsiElement()); + public JetIntentionAction createAction(DiagnosticWithPsiElement diagnostic) { + assert diagnostic.getPsiElement() instanceof JetFunction; + return new AddFunctionBodyFix((JetFunction) diagnostic.getPsiElement()); } }; } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/AddModifierFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/AddModifierFix.java index de64087a558..42e28ef25eb 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/AddModifierFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/AddModifierFix.java @@ -4,11 +4,13 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiNameIdentifierOwner; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.diagnostics.DiagnosticWithPsiElement; import org.jetbrains.jet.lang.psi.JetModifierList; import org.jetbrains.jet.lang.psi.JetModifierListOwner; +import org.jetbrains.jet.lang.psi.JetPropertyAccessor; import org.jetbrains.jet.lang.psi.JetPsiFactory; import org.jetbrains.jet.lexer.JetKeywordToken; import org.jetbrains.jet.lexer.JetToken; @@ -17,19 +19,39 @@ import org.jetbrains.jet.lexer.JetTokens; /** * @author svtk */ -public class AddModifierFix extends ModifierFix { +public class AddModifierFix extends JetIntentionAction { + private final JetKeywordToken modifier; private final JetToken[] modifiersThanCanBeReplaced; private AddModifierFix(@NotNull JetModifierListOwner element, JetKeywordToken modifier, JetToken[] modifiersThanCanBeReplaced) { - super(element, modifier); + super(element); + this.modifier = modifier; this.modifiersThanCanBeReplaced = modifiersThanCanBeReplaced; } + @NotNull + /*package*/ static String getElementName(JetModifierListOwner modifierListOwner) { + String name = null; + if (modifierListOwner instanceof PsiNameIdentifierOwner) { + PsiElement nameIdentifier = ((PsiNameIdentifierOwner) modifierListOwner).getNameIdentifier(); + if (nameIdentifier != null) { + name = nameIdentifier.getText(); + } + } + else if (modifierListOwner instanceof JetPropertyAccessor) { + name = ((JetPropertyAccessor) modifierListOwner).getNamePlaceholder().getText(); + } + if (name == null) { + name = modifierListOwner.getText(); + } + return "'" + name + "'"; + } + @NotNull @Override public String getText() { if (modifier == JetTokens.ABSTRACT_KEYWORD || modifier == JetTokens.OPEN_KEYWORD) { - return "Make " + getElementName() + " " + modifier.getValue(); + return "Make " + getElementName(element) + " " + modifier.getValue(); } return "Add '" + modifier.getValue() + "' modifier"; } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/AddReturnTypeFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/AddReturnTypeFix.java new file mode 100644 index 00000000000..7314585e233 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/AddReturnTypeFix.java @@ -0,0 +1,92 @@ +package org.jetbrains.jet.plugin.quickfix; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.diagnostics.DiagnosticParameters; +import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters; +import org.jetbrains.jet.lang.diagnostics.DiagnosticWithPsiElement; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.types.JetType; + +/** +* @author svtk +*/ +public class AddReturnTypeFix extends JetIntentionAction { + private JetType type; + + public AddReturnTypeFix(@NotNull JetNamedDeclaration element, JetType type) { + super(element); + this.type = type; + } + + @NotNull + @Override + public String getText() { + return "Add return type declaration"; + } + + @NotNull + @Override + public String getFamilyName() { + return "Add return type declaration"; + } + + @Override + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + PsiElement newElement; + if (element instanceof JetProperty) { + newElement = addPropertyType(project, (JetProperty) element, type); + } + else { + assert element instanceof JetFunction; + newElement = addFunctionType(project, (JetFunction) element, type); + } + ImportClassHelper.perform(type, element, newElement); + } + + @Override + public boolean startInWriteAction() { + return true; + } + + public static JetProperty addPropertyType(Project project, JetProperty property, JetType type) { + JetProperty newProperty = (JetProperty) property.copy(); + JetTypeReference typeReference = JetPsiFactory.createType(project, type.toString()); + Pair colon = JetPsiFactory.createColon(project); + PsiElement nameIdentifier = newProperty.getNameIdentifier(); + addTypeReference(newProperty, typeReference, colon, nameIdentifier); + return newProperty; + } + + public static JetFunction addFunctionType(Project project, JetFunction function, JetType type) { + JetFunction newFunction = (JetFunction) function.copy(); + JetTypeReference typeReference = JetPsiFactory.createType(project, type.toString()); + Pair colon = JetPsiFactory.createColon(project); + JetParameterList valueParameterList = newFunction.getValueParameterList(); + addTypeReference(newFunction, typeReference, colon, valueParameterList); + return newFunction; + } + + private static void addTypeReference(JetNamedDeclaration element, JetTypeReference typeReference, Pair colon, PsiElement anchor) { + assert anchor != null; + element.addAfter(typeReference, anchor); + element.addRangeAfter(colon.getFirst(), colon.getSecond(), anchor); + } + + public static JetIntentionActionFactory createFactory() { + return new JetIntentionActionFactory() { + @Override + public JetIntentionAction createAction(DiagnosticWithPsiElement diagnostic) { + assert diagnostic.getPsiElement() instanceof JetNamedDeclaration; + DiagnosticWithParameters diagnosticWithParameters = assertAndCastToDiagnosticWithParameters(diagnostic, DiagnosticParameters.TYPE); + JetType type = diagnosticWithParameters.getParameter(DiagnosticParameters.TYPE); + return new AddReturnTypeFix((JetNamedDeclaration) diagnostic.getPsiElement(), type); + } + }; + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ModifierFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ModifierFix.java deleted file mode 100644 index fa1c38e7a6c..00000000000 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ModifierFix.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.jetbrains.jet.plugin.quickfix; - -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiNameIdentifierOwner; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.psi.JetModifierListOwner; -import org.jetbrains.jet.lang.psi.JetPropertyAccessor; -import org.jetbrains.jet.lexer.JetKeywordToken; - -/** - * @author svtk - */ -public abstract class ModifierFix extends JetIntentionAction { - protected final JetKeywordToken modifier; - - protected ModifierFix(@NotNull JetModifierListOwner element, JetKeywordToken modifier) { - super(element); - this.modifier = modifier; - } - - @NotNull - protected String getElementName() { - String name = null; - if (element instanceof PsiNameIdentifierOwner) { - PsiElement nameIdentifier = ((PsiNameIdentifierOwner) element).getNameIdentifier(); - if (nameIdentifier != null) { - name = nameIdentifier.getText(); - } - } - else if (element instanceof JetPropertyAccessor) { - name = ((JetPropertyAccessor) element).getNamePlaceholder().getText(); - } - if (name == null) { - name = element.getText(); - } - return "'" + name + "'"; - } -} diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixUtil.java b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixUtil.java index 02ffaa2b339..9d7df6ff1b5 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixUtil.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixUtil.java @@ -1,9 +1,11 @@ package org.jetbrains.jet.plugin.quickfix; +import com.intellij.extapi.psi.ASTDelegatePsiElement; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiWhiteSpace; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.diagnostics.DiagnosticParameter; @@ -69,4 +71,12 @@ public class QuickFixUtil { } }; } + + public static boolean removePossiblyWhiteSpace(ASTDelegatePsiElement element, PsiElement possiblyWhiteSpace) { + if (possiblyWhiteSpace instanceof PsiWhiteSpace) { + element.deleteChildInternal(possiblyWhiteSpace.getNode()); + return true; + } + return false; + } } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java index a2f4fb48753..76f37013470 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java @@ -29,7 +29,7 @@ public class QuickFixes { } static { - JetIntentionActionFactory removeAbstractModifierFactory = RemoveModifierFix.createFactory(JetTokens.ABSTRACT_KEYWORD); + JetIntentionActionFactory removeAbstractModifierFactory = RemoveModifierFix.createRemoveModifierFromListOwnerFactory(JetTokens.ABSTRACT_KEYWORD); JetIntentionActionFactory addAbstractModifierFactory = AddModifierFix.createFactory(JetTokens.ABSTRACT_KEYWORD, new JetToken[]{JetTokens.OPEN_KEYWORD, JetTokens.FINAL_KEYWORD}); add(Errors.ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS, removeAbstractModifierFactory); @@ -53,22 +53,21 @@ public class QuickFixes { add(Errors.ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS, removeAbstractModifierFactory); add(Errors.ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS, addAbstractToClassFactory); - JetIntentionActionFactory removeFunctionBodyFactory = RemoveFunctionBodyFix.createFactory(); + JetIntentionActionFactory removeFunctionBodyFactory = RemoveFunctionBodyFix.createFactory(); add(Errors.ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS, removeAbstractModifierFactory); add(Errors.ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS, addAbstractToClassFactory); add(Errors.ABSTRACT_FUNCTION_WITH_BODY, removeAbstractModifierFactory); add(Errors.ABSTRACT_FUNCTION_WITH_BODY, removeFunctionBodyFactory); - JetIntentionActionFactory addFunctionBodyFactory = AddFunctionBodyFix.createFactory(); + JetIntentionActionFactory addFunctionBodyFactory = AddFunctionBodyFix.createFactory(); add(Errors.NON_ABSTRACT_FUNCTION_WITH_NO_BODY, addAbstractModifierFactory); add(Errors.NON_ABSTRACT_FUNCTION_WITH_NO_BODY, addFunctionBodyFactory); add(Errors.NON_MEMBER_ABSTRACT_FUNCTION, removeAbstractModifierFactory); - add(Errors.NON_MEMBER_ABSTRACT_ACCESSOR, removeAbstractModifierFactory); add(Errors.NON_MEMBER_FUNCTION_NO_BODY, addFunctionBodyFactory); - add(Errors.NOTHING_TO_OVERRIDE, RemoveModifierFix.createFactory(JetTokens.OVERRIDE_KEYWORD)); + add(Errors.NOTHING_TO_OVERRIDE, RemoveModifierFix.createRemoveModifierFromListFactory(JetTokens.OVERRIDE_KEYWORD)); add(Errors.VIRTUAL_MEMBER_HIDDEN, AddModifierFix.createFactory(JetTokens.OVERRIDE_KEYWORD, new JetToken[] {JetTokens.OPEN_KEYWORD})); add(Errors.VAL_WITH_SETTER, ChangeVariableMutabilityFix.createFactory()); @@ -84,10 +83,10 @@ public class QuickFixes { add(Errors.UNNECESSARY_SAFE_CALL, ReplaceSafeCallToDotCall.createFactory()); - JetIntentionActionFactory removeRedundantModifierFactory = RemoveRedundantModifierFix.createFactory(); + JetIntentionActionFactory removeRedundantModifierFactory = RemoveModifierFix.createRemoveModifierFromListFactory(true); add(Errors.REDUNDANT_MODIFIER, removeRedundantModifierFactory); add(Errors.REDUNDANT_MODIFIER_IN_TRAIT, removeRedundantModifierFactory); - add(Errors.TRAIT_CAN_NOT_BE_FINAL, RemoveModifierFix.createFactory(JetTokens.FINAL_KEYWORD)); + add(Errors.TRAIT_CAN_NOT_BE_FINAL, RemoveModifierFix.createRemoveModifierFromListOwnerFactory(JetTokens.FINAL_KEYWORD)); add(Errors.PROPERTY_INITIALIZER_NO_PRIMARY_CONSTRUCTOR, RemovePartsFromPropertyFix.createRemoveInitializerFactory()); @@ -96,14 +95,15 @@ public class QuickFixes { add(Errors.PRIMARY_CONSTRUCTOR_MISSING_STATEFUL_PROPERTY, addPrimaryConstructorFactory); JetIntentionActionFactory addOpenModifierFactory = AddModifierFix.createFactory(JetTokens.OPEN_KEYWORD, new JetToken[]{JetTokens.FINAL_KEYWORD}); - JetIntentionActionFactory removeOpenModifierFactory = RemoveModifierFix.createFactory(JetTokens.OPEN_KEYWORD); + JetIntentionActionFactory removeOpenModifierFactory = RemoveModifierFix.createRemoveModifierFromListOwnerFactory(JetTokens.OPEN_KEYWORD); add(Errors.NON_FINAL_MEMBER_IN_FINAL_CLASS, QuickFixUtil.createFactoryRedirectingAdditionalInfoToAnotherFactory(addOpenModifierFactory, DiagnosticParameters.CLASS)); add(Errors.NON_FINAL_MEMBER_IN_FINAL_CLASS, removeOpenModifierFactory); - add(Errors.NON_FINAL_ACCESSOR_OF_FINAL_PROPERTY, QuickFixUtil.createFactoryRedirectingAdditionalInfoToAnotherFactory(addOpenModifierFactory, DiagnosticParameters.PROPERTY)); - add(Errors.NON_FINAL_ACCESSOR_OF_FINAL_PROPERTY, removeOpenModifierFactory); - add(Errors.ABSTRACT_ACCESSOR_OF_NON_ABSTRACT_PROPERTY, QuickFixUtil.createFactoryRedirectingAdditionalInfoToAnotherFactory(addAbstractModifierFactory, DiagnosticParameters.PROPERTY)); - add(Errors.ABSTRACT_ACCESSOR_OF_NON_ABSTRACT_PROPERTY, removeAbstractModifierFactory); + JetIntentionActionFactory removeModifierFactory = RemoveModifierFix.createRemoveModifierFromListFactory(); + add(Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY, removeModifierFactory); + add(Errors.REDUNDANT_MODIFIER_IN_GETTER, removeRedundantModifierFactory); + add(Errors.ILLEGAL_MODIFIER, removeModifierFactory); + + add(Errors.PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE, AddReturnTypeFix.createFactory()); } -} - +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveFunctionBodyFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveFunctionBodyFix.java index 4b7bb7fd187..35e58499ddc 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveFunctionBodyFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveFunctionBodyFix.java @@ -4,18 +4,22 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiWhiteSpace; +import com.intellij.psi.impl.source.tree.LeafPsiElement; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.diagnostics.DiagnosticWithPsiElement; -import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.psi.JetElement; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.JetFunction; +import org.jetbrains.jet.lexer.JetTokens; /** * @author svtk */ -public class RemoveFunctionBodyFix extends JetIntentionAction { +public class RemoveFunctionBodyFix extends JetIntentionAction { - public RemoveFunctionBodyFix(@NotNull JetFunctionOrPropertyAccessor element) { + public RemoveFunctionBodyFix(@NotNull JetFunction element) { super(element); } @@ -39,25 +43,41 @@ public class RemoveFunctionBodyFix extends JetIntentionAction createFactory() { - return new JetIntentionActionFactory() { + private static boolean removePossiblyEquationSign(@NotNull JetElement element, @Nullable PsiElement possiblyEq) { + if (possiblyEq instanceof LeafPsiElement && ((LeafPsiElement)possiblyEq).getElementType() == JetTokens.EQ) { + QuickFixUtil.removePossiblyWhiteSpace(element, possiblyEq.getNextSibling()); + element.deleteChildInternal(possiblyEq.getNode()); + return true; + } + return false; + } + + public static JetIntentionActionFactory createFactory() { + return new JetIntentionActionFactory() { @Override - public JetIntentionAction createAction(DiagnosticWithPsiElement diagnostic) { - assert diagnostic.getPsiElement() instanceof JetFunctionOrPropertyAccessor; - return new RemoveFunctionBodyFix((JetFunctionOrPropertyAccessor) diagnostic.getPsiElement()); + public JetIntentionAction createAction(DiagnosticWithPsiElement diagnostic) { + assert diagnostic.getPsiElement() instanceof JetFunction; + return new RemoveFunctionBodyFix((JetFunction) diagnostic.getPsiElement()); } }; } -} +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveModifierFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveModifierFix.java index ac68ec8c38c..79cb415fee0 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveModifierFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveModifierFix.java @@ -1,14 +1,15 @@ package org.jetbrains.jet.plugin.quickfix; -import com.intellij.extapi.psi.ASTDelegatePsiElement; import com.intellij.lang.ASTNode; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiWhiteSpace; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.diagnostics.DiagnosticParameters; +import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters; import org.jetbrains.jet.lang.diagnostics.DiagnosticWithPsiElement; import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.psi.JetModifierList; @@ -20,35 +21,31 @@ import org.jetbrains.jet.lexer.JetTokens; /** * @author svtk */ -public class RemoveModifierFix extends ModifierFix { +public class RemoveModifierFix { + private final JetKeywordToken modifier; + private final boolean isRedundant; - public RemoveModifierFix(@NotNull JetModifierListOwner element, JetKeywordToken modifier) { - super(element, modifier); + public RemoveModifierFix(JetKeywordToken modifier, boolean isRedundant) { + this.modifier = modifier; + this.isRedundant = isRedundant; } - @NotNull - @Override - public String getText() { - if (modifier == JetTokens.ABSTRACT_KEYWORD || modifier == JetTokens.OPEN_KEYWORD) { - return "Make " + getElementName() + " not " + modifier.getValue(); + private static String makeText(@Nullable JetModifierListOwner element, JetKeywordToken modifier, boolean isRedundant) { + if (isRedundant) { + return "Remove redundant '" + modifier.getValue() + "' modifier"; + } + if (element != null && modifier == JetTokens.ABSTRACT_KEYWORD || modifier == JetTokens.OPEN_KEYWORD) { + return "Make " + AddModifierFix.getElementName(element) + " not " + modifier.getValue(); } return "Remove '" + modifier.getValue() + "' modifier"; } - - @NotNull - @Override - public String getFamilyName() { - return "Remove modifier"; - } - - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - JetModifierListOwner newElement = (JetModifierListOwner) element.copy(); - element.replace(removeModifier(newElement, modifier)); + + private static String getFamilyName() { + return "Remove modifier fix"; } @NotNull - /*package*/ static T removeModifier(T element, JetToken modifier) { + private static T removeModifier(T element, JetToken modifier) { JetModifierList modifierList = element.getModifierList(); assert modifierList != null; removeModifierFromList(modifierList, modifier); @@ -56,38 +53,128 @@ public class RemoveModifierFix extends ModifierFix { PsiElement whiteSpace = modifierList.getNextSibling(); assert element instanceof JetElement; ((JetElement) element).deleteChildInternal(modifierList.getNode()); - removeWhiteSpace((JetElement) element, whiteSpace); + QuickFixUtil.removePossiblyWhiteSpace((JetElement) element, whiteSpace); } return element; } - /*package*/ static JetModifierList removeModifierFromList(@NotNull JetModifierList modifierList, JetToken modifier) { + @NotNull + private static JetModifierList removeModifierFromList(@NotNull JetModifierList modifierList, JetToken modifier) { assert modifierList.hasModifier(modifier); ASTNode modifierNode = modifierList.getModifierNode(modifier); PsiElement whiteSpace = modifierNode.getPsi().getNextSibling(); - boolean wsRemoved = removeWhiteSpace(modifierList, whiteSpace); + boolean wsRemoved = QuickFixUtil.removePossiblyWhiteSpace(modifierList, whiteSpace); modifierList.deleteChildInternal(modifierNode); if (!wsRemoved) { - removeWhiteSpace(modifierList, modifierList.getLastChild()); + QuickFixUtil.removePossiblyWhiteSpace(modifierList, modifierList.getLastChild()); } return modifierList; } - - private static boolean removeWhiteSpace(ASTDelegatePsiElement element, PsiElement subElement) { - if (subElement instanceof PsiWhiteSpace) { - element.deleteChildInternal(subElement.getNode()); - return true; + + private class RemoveModifierFromListOwner extends JetIntentionAction { + public RemoveModifierFromListOwner(@NotNull JetModifierListOwner element) { + super(element); + } + + @NotNull + @Override + public String getText() { + return makeText(element, modifier, isRedundant); + } + + @NotNull + @Override + public String getFamilyName() { + return RemoveModifierFix.getFamilyName(); + } + + @Override + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + JetModifierListOwner newElement = (JetModifierListOwner) element.copy(); + element.replace(removeModifier(newElement, modifier)); } - return false; } - public static JetIntentionActionFactory createFactory(final JetKeywordToken modifier) { + private class RemoveModifierFromList extends JetIntentionAction { + public RemoveModifierFromList(@NotNull JetModifierList element) { + super(element); + } + + @NotNull + @Override + public String getText() { + return makeText(null, modifier, isRedundant); + } + + @NotNull + @Override + public String getFamilyName() { + return RemoveModifierFix.getFamilyName(); + } + + @Override + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + JetModifierList newElement = (JetModifierList) element.copy(); + element.replace(RemoveModifierFix.removeModifierFromList(newElement, modifier)); + } + } + + + public static JetIntentionActionFactory createRemoveModifierFromListOwnerFactory(final JetKeywordToken modifier, final boolean isRedundant) { return new JetIntentionActionFactory() { @Override public JetIntentionAction createAction(DiagnosticWithPsiElement diagnostic) { assert diagnostic.getPsiElement() instanceof JetModifierListOwner; - return new RemoveModifierFix((JetModifierListOwner) diagnostic.getPsiElement(), modifier); + return new RemoveModifierFix(modifier, isRedundant).new RemoveModifierFromListOwner((JetModifierListOwner) diagnostic.getPsiElement()); } }; } -} + + private static RemoveModifierFix createRemoveModifierFixFromDiagnostic(DiagnosticWithPsiElement diagnostic, boolean isRedundant) { + DiagnosticWithParameters diagnosticWithParameters = JetIntentionAction.assertAndCastToDiagnosticWithParameters(diagnostic, DiagnosticParameters.MODIFIER); + JetKeywordToken modifier = diagnosticWithParameters.getParameter(DiagnosticParameters.MODIFIER); + return new RemoveModifierFix(modifier, isRedundant); + } + + public static JetIntentionActionFactory createRemoveModifierFromListOwnerFactory(final boolean isRedundant) { + return new JetIntentionActionFactory() { + @Override + public JetIntentionAction createAction(DiagnosticWithPsiElement diagnostic) { + assert diagnostic.getPsiElement() instanceof JetModifierListOwner; + return createRemoveModifierFixFromDiagnostic(diagnostic, isRedundant).new RemoveModifierFromListOwner((JetModifierListOwner) diagnostic.getPsiElement()); + } + }; + } + + public static JetIntentionActionFactory createRemoveModifierFromListFactory(final boolean isRedundant) { + return new JetIntentionActionFactory() { + @Override + public JetIntentionAction createAction(DiagnosticWithPsiElement diagnostic) { + assert diagnostic.getPsiElement() instanceof JetModifierList; + return createRemoveModifierFixFromDiagnostic(diagnostic, isRedundant).new RemoveModifierFromList((JetModifierList) diagnostic.getPsiElement()); + } + }; + } + + public static JetIntentionActionFactory createRemoveModifierFromListFactory(final JetKeywordToken modifier, final boolean isRedundant) { + return new JetIntentionActionFactory() { + @Override + public JetIntentionAction createAction(DiagnosticWithPsiElement diagnostic) { + assert diagnostic.getPsiElement() instanceof JetModifierList; + return new RemoveModifierFix(modifier, isRedundant).new RemoveModifierFromList((JetModifierList) diagnostic.getPsiElement()); + } + }; + } + + public static JetIntentionActionFactory createRemoveModifierFromListOwnerFactory(final JetKeywordToken modifier) { + return createRemoveModifierFromListOwnerFactory(modifier, false); + } + + public static JetIntentionActionFactory createRemoveModifierFromListFactory() { + return createRemoveModifierFromListFactory(false); + } + + public static JetIntentionActionFactory createRemoveModifierFromListFactory(final JetKeywordToken modifier) { + return createRemoveModifierFromListFactory(modifier, false); + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/RemovePartsFromPropertyFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/RemovePartsFromPropertyFix.java index 34c99ff3155..f9e3afc1295 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/RemovePartsFromPropertyFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/RemovePartsFromPropertyFix.java @@ -2,7 +2,6 @@ package org.jetbrains.jet.plugin.quickfix; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.util.IncorrectOperationException; @@ -97,7 +96,7 @@ public class RemovePartsFromPropertyFix extends JetIntentionAction newElement.deleteChildRange(nextSibling, initializer); if (newElement.getPropertyTypeRef() == null && type != null) { - newElement = addPropertyType(project, newElement, type); + newElement = AddReturnTypeFix.addPropertyType(project, newElement, type); needImport = true; } } @@ -108,17 +107,6 @@ public class RemovePartsFromPropertyFix extends JetIntentionAction } } - public static JetProperty addPropertyType(Project project, JetProperty property, JetType type) { - JetProperty newProperty = (JetProperty) property.copy(); - JetTypeReference typeReference = JetPsiFactory.createType(project, type.toString()); - Pair colon = JetPsiFactory.createColon(project); - PsiElement nameIdentifier = newProperty.getNameIdentifier(); - assert nameIdentifier != null; - newProperty.addAfter(typeReference, nameIdentifier); - newProperty.addRangeAfter(colon.getFirst(), colon.getSecond(), nameIdentifier); - return newProperty; - } - public static JetIntentionActionFactory createFactory() { return new JetIntentionActionFactory() { @Override diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveRedundantModifierFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveRedundantModifierFix.java deleted file mode 100644 index 4c895b3ebcf..00000000000 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveRedundantModifierFix.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.jetbrains.jet.plugin.quickfix; - -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.util.IncorrectOperationException; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.diagnostics.DiagnosticParameters; -import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters; -import org.jetbrains.jet.lang.diagnostics.DiagnosticWithPsiElement; -import org.jetbrains.jet.lang.psi.JetModifierList; -import org.jetbrains.jet.lexer.JetKeywordToken; - -/** - * @author svtk - */ -public class RemoveRedundantModifierFix extends JetIntentionAction { - private JetKeywordToken redundantModifier; - public RemoveRedundantModifierFix(@NotNull JetModifierList element, @NotNull JetKeywordToken redundantModifier) { - super(element); - this.redundantModifier = redundantModifier; - } - - @NotNull - @Override - public String getText() { - return "Remove redundant '" + redundantModifier + "' modifier"; - } - - @NotNull - @Override - public String getFamilyName() { - return "Remove redundant modifier"; - } - - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - JetModifierList newElement = (JetModifierList) element.copy(); - element.replace(RemoveModifierFix.removeModifierFromList(newElement, redundantModifier)); - } - - public static JetIntentionActionFactory createFactory() { - return new JetIntentionActionFactory() { - @Override - public JetIntentionAction createAction(DiagnosticWithPsiElement diagnostic) { - assert diagnostic.getPsiElement() instanceof JetModifierList; - DiagnosticWithParameters diagnosticWithParameters = assertAndCastToDiagnosticWithParameters(diagnostic, DiagnosticParameters.MODIFIER); - JetKeywordToken modifier = diagnosticWithParameters.getParameter(DiagnosticParameters.MODIFIER); - return new RemoveRedundantModifierFix((JetModifierList) diagnostic.getPsiElement(), modifier); - } - }; - } -} diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java index a771388c338..9916a18468f 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java @@ -11,6 +11,7 @@ import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetReferenceExpression; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.plugin.AnalyzerFacade; import java.util.Collection; @@ -80,7 +81,7 @@ public abstract class JetPsiReference implements PsiPolyVariantReference { if (psiElement != null) { return psiElement; } - Collection declarationDescriptors = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, myExpression); + Collection> declarationDescriptors = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, myExpression); if (declarationDescriptors != null) return null; return file; } @@ -88,12 +89,12 @@ public abstract class JetPsiReference implements PsiPolyVariantReference { protected ResolveResult[] doMultiResolve() { JetFile file = (JetFile) getElement().getContainingFile(); BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file); - Collection declarationDescriptors = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, myExpression); - if (declarationDescriptors == null) return ResolveResult.EMPTY_ARRAY; - ResolveResult[] results = new ResolveResult[declarationDescriptors.size()]; + Collection> resolvedCalls = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, myExpression); + if (resolvedCalls == null) return ResolveResult.EMPTY_ARRAY; + ResolveResult[] results = new ResolveResult[resolvedCalls.size()]; int i = 0; - for (DeclarationDescriptor descriptor : declarationDescriptors) { - PsiElement element = bindingContext.get(DESCRIPTOR_TO_DECLARATION, descriptor); + for (ResolvedCall resolvedCall : resolvedCalls) { + PsiElement element = bindingContext.get(DESCRIPTOR_TO_DECLARATION, resolvedCall.getResultingDescriptor()); if (element != null) { results[i] = new PsiElementResolveResult(element, true); i++; diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java index b90af3696ef..55d454b3c50 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java @@ -38,7 +38,9 @@ class JetSimpleNameReference extends JetPsiReference { @Override public TextRange getRangeInElement() { - return new TextRange(0, getElement().getTextLength()); + PsiElement element = getElement(); + if (element == null) return null; + return new TextRange(0, element.getTextLength()); } @NotNull diff --git a/idea/src/org/jetbrains/jet/plugin/run/JetRunConfiguration.java b/idea/src/org/jetbrains/jet/plugin/run/JetRunConfiguration.java index 533277da3bb..e38a9b8fd96 100644 --- a/idea/src/org/jetbrains/jet/plugin/run/JetRunConfiguration.java +++ b/idea/src/org/jetbrains/jet/plugin/run/JetRunConfiguration.java @@ -2,7 +2,7 @@ package org.jetbrains.jet.plugin.run; import com.intellij.execution.ExecutionException; import com.intellij.execution.Executor; -import com.intellij.execution.RunConfigurationExtension; +import com.intellij.execution.JavaRunConfigurationExtensionManager; import com.intellij.execution.configurations.*; import com.intellij.execution.filters.TextConsoleBuilderFactory; import com.intellij.execution.runners.ExecutionEnvironment; @@ -49,14 +49,15 @@ public class JetRunConfiguration extends ModuleBasedConfiguration ===================== -== 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/Constructors.jet b/idea/testData/checker/Constructors.jet index 7c6e8582a56..6891d8f1f98 100644 --- a/idea/testData/checker/Constructors.jet +++ b/idea/testData/checker/Constructors.jet @@ -23,7 +23,7 @@ class WithPC1(a : Int) { this(s : String) : this(1) {} - this(b : Char) : this("", 2) {} + this(b : Char) : this("", 2) {} this(b : Byte) : this(""), this(1) {} } diff --git a/idea/testData/checker/ExtensionFunctions.jet b/idea/testData/checker/ExtensionFunctions.jet index 0464054f743..f1ec6d22908 100644 --- a/idea/testData/checker/ExtensionFunctions.jet +++ b/idea/testData/checker/ExtensionFunctions.jet @@ -16,7 +16,7 @@ class A fun A.plus(a : Any) { 1.foo() - true.foo() + true.foo() 1 } @@ -55,10 +55,10 @@ namespace null_safety { val command = parse("") - command.foo + command.foo command.equals(null) - command?.equals(null) + command?.equals(null) command.equals1(null) command?.equals1(null) 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/checker/When.jet b/idea/testData/checker/When.jet index 53177aea4ec..a7bd2a87103 100644 --- a/idea/testData/checker/When.jet +++ b/idea/testData/checker/When.jet @@ -1,3 +1,5 @@ +fun Int.foo() : Boolean = true + fun foo() : Int { val s = "" val x = 1 @@ -17,7 +19,7 @@ fun foo() : Int { else => 1 } return when (x?:null) { - .equals(1) => 1 + .foo() => 1 ?.equals(1).equals(2) => 1 } } diff --git a/idea/testData/checker/infos/Autocasts.jet b/idea/testData/checker/infos/Autocasts.jet index 7cf18aadd48..062b26b75a2 100644 --- a/idea/testData/checker/infos/Autocasts.jet +++ b/idea/testData/checker/infos/Autocasts.jet @@ -1,4 +1,4 @@ -open class A() { +open class A() { fun foo() {} } @@ -9,25 +9,25 @@ class B() : A() { fun f9() { val a : A? a?.foo() - a?.bar() + a?.bar() if (a is B) { a.bar() - a.foo() + a.foo() } a?.foo() - a?.bar() + a?.bar() if (!(a is B)) { - a?.bar() + a?.bar() a?.foo() } if (!(a is B) || a.bar() == ()) { - a?.bar() + a?.bar() } if (!(a is B)) { return; } a.bar() - a.foo() + a.foo() } fun f10() { @@ -47,19 +47,17 @@ class C() : A() { } fun f10(a : A?) { - if (a is B) { if (a is C) { a.bar(); } - } } fun f11(a : A?) { when (a) { is B => a.bar() - is A => a.foo() - is Any => a.foo() - is Any? => a.bar() + is A => a.foo() + is Any => a.foo() + is Any? => a.bar() else => a?.foo() } } @@ -67,21 +65,21 @@ fun f11(a : A?) { fun f12(a : A?) { when (a) { is B => a.bar() - is A => a.foo() - is Any => a.foo(); - is Any? => a.bar() - is val c : B => c.foo() + is A => a.foo() + is Any => a.foo(); + is Any? => a.bar() + is val c : B => c.foo() is val c is C => c.bar() is val c is C => a.bar() else => a?.foo() } if (a is val b) { - a?.bar() + a?.bar() b?.foo() } if (a is val b is B) { - b.foo() + b.foo() a.bar() b.bar() } @@ -89,41 +87,41 @@ fun f12(a : A?) { fun f13(a : A?) { if (a is val c is B) { - c.foo() + c.foo() c.bar() } else { a?.foo() - c.bar() + c.bar() } a?.foo() if (!(a is val c is B)) { a?.foo() - c.bar() + c.bar() } else { - a.foo() - c.bar() + a.foo() + c.bar() } a?.foo() - if (a is val c is B && a.foo() == () && c.bar() == ()) { - c.foo() + if (a is val c is B && a.foo() == () && c.bar() == ()) { + c.foo() c.bar() } else { a?.foo() - c.bar() + c.bar() } if (!(a is val c is B) || !(a is val x is C)) { - x - c + x + c } else { - x - c + x + c } if (!(a is val c is B) || !(a is val c is C)) { @@ -131,38 +129,38 @@ fun f13(a : A?) { if (!(a is val c is B)) return a.bar() - c.foo() - c.bar() + c.foo() + c.bar() } fun f14(a : A?) { while (!(a is val c is B)) { } a.bar() - c.bar() + c.bar() } fun f15(a : A?) { do { } while (!(a is val c is B)) a.bar() - c.bar() + c.bar() } fun getStringLength(obj : Any) : Char? { if (obj !is String) return null - return obj.get(0) // no cast to String is needed + return obj.get(0) // no cast to String is needed } fun toInt(i: Int?): Int = if (i != null) i else 0 fun illegalWhenBody(a: Any): Int = when(a) { is Int => a - is String => a + is String => a } fun illegalWhenBlock(a: Any): Int { when(a) { is Int => return a - is String => return a + is String => return a } } fun declarations(a: Any?) { @@ -188,17 +186,17 @@ fun vars(a: Any?) { } fun tuples(a: Any?) { if (a != null) { - val s: (Any, String) = (a, a) + val s: (Any, String) = (a, a) } if (a is String) { - val s: (Any, String) = (a, a) + val s: (Any, String) = (a, a) } - fun illegalTupleReturnType(): (Any, String) = (a, a) + fun illegalTupleReturnType(): (Any, String) = (a, a) if (a is String) { - fun legalTupleReturnType(): (Any, String) = (a, a) + fun legalTupleReturnType(): (Any, String) = (a, a) } - val illegalFunctionLiteral: Function0 = { a } - val illegalReturnValueInFunctionLiteral: Function0 = { (): Int => a } + val illegalFunctionLiteral: Function0 = { a } + val illegalReturnValueInFunctionLiteral: Function0 = { (): Int => a } if (a is Int) { val legalFunctionLiteral: Function0 = { a } @@ -213,43 +211,43 @@ fun returnFunctionLiteral(a: Any?): Function0 = if (a is Int) { (): Int => a } else { () => 1 } -fun illegalTupleReturnType(a: Any): (Any, String) = (a, a) +fun illegalTupleReturnType(a: Any): (Any, String) = (a, a) fun declarationInsidePattern(x: (Any, Any)): String = when(x) { is (val a is String, *) => a; else => "something" } fun mergeAutocasts(a: Any?) { if (a is String || a is Int) { - a.compareTo("") + a.compareTo("") a.toString() } if (a is Int || a is String) { - a.compareTo("") + a.compareTo("") } when (a) { - is String, is Any => a.compareTo("") + is String, is Any => a.compareTo("") } if (a is String && a is Any) { val i: Int = a.compareTo("") } if (a is String && a.compareTo("") == 0) {} - if (a is String || a.compareTo("") == 0) {} + if (a is String || a.compareTo("") == 0) {} } //mutability fun f(): String { var a: Any = 11 if (a is String) { - val i: String = a - a.compareTo("f") - val f: Function0 = { a } - return a + val i: String = a + a.compareTo("f") + val f: Function0 = { a } + return a } return "" } fun foo(var a: Any): Int { if (a is Int) { - return a + return a } return 1 } \ No newline at end of file diff --git a/idea/testData/checker/infos/PropertiesWithBackingFields.jet b/idea/testData/checker/infos/PropertiesWithBackingFields.jet index 294ea276524..5e9b644e94c 100644 --- a/idea/testData/checker/infos/PropertiesWithBackingFields.jet +++ b/idea/testData/checker/infos/PropertiesWithBackingFields.jet @@ -35,8 +35,6 @@ var v5 : Int get() = 1; set(x){$v5 = x} var v6 : Int get() = $v6 + 1; set(x){} - abstract val v7 : Int abstract get - abstract var v8 : Int abstract get abstract set var v9 : Int set var v10 : Int get diff --git a/idea/testData/checker/infos/WrapIntoRef.jet b/idea/testData/checker/infos/WrapIntoRef.jet new file mode 100644 index 00000000000..47613236fa0 --- /dev/null +++ b/idea/testData/checker/infos/WrapIntoRef.jet @@ -0,0 +1,18 @@ +fun notContainsBreak() { + var a = 1 + val v = { + a = 2 + } + + var x = 1 + val b = object { + fun foo() { + x = 2 + } + } + + var y = 1 + fun foo() { + y = 1 + } +} diff --git a/idea/testData/checker/regression/Jet67.jet b/idea/testData/checker/regression/Jet67.jet index 7c2248a5f6a..94549ab8df9 100644 --- a/idea/testData/checker/regression/Jet67.jet +++ b/idea/testData/checker/regression/Jet67.jet @@ -1,4 +1,4 @@ abstract class XXX { - abstract val a : Int abstract get + abstract val a : Int get } diff --git a/idea/testData/checkerWithErrorTypes/full/Abstract.jet b/idea/testData/checkerWithErrorTypes/full/Abstract.jet index a1c73c553d7..e1633f74b05 100644 --- a/idea/testData/checkerWithErrorTypes/full/Abstract.jet +++ b/idea/testData/checkerWithErrorTypes/full/Abstract.jet @@ -29,19 +29,19 @@ class MyClass() { abstract fun j() {} //property accessors - var i: Int abstract get abstract set - var i1: Int = 0; abstract get abstract set + var i: Int abstract get abstract set + var i1: Int = 0; abstract get abstract set - var j: Int get() = i; abstract set - var j1: Int = 0; get() = i; abstract set + var j: Int get() = i; abstract set + var j1: Int = 0; get() = i; abstract set - var k: Int abstract set - var k1: Int = 0; abstract set + var k: Int abstract set + var k1: Int = 0; abstract set - var l: Int abstract get abstract set - var l1: Int = 0; abstract get abstract set + var l: Int abstract get abstract set + var l1: Int = 0; abstract get abstract set - var n: Int abstract get abstract set(v: Int) {} + var n: Int abstract get abstract set(v: Int) {} } abstract class MyAbstractClass() { @@ -73,19 +73,19 @@ abstract class MyAbstractClass() { abstract fun j() {} //property accessors - var i: Int abstract get abstract set - var i1: Int = 0; abstract get abstract set + var i: Int abstract get abstract set + var i1: Int = 0; abstract get abstract set - var j: Int get() = i; abstract set - var j1: Int get() = i; abstract set + var j: Int get() = i; abstract set + var j1: Int get() = i; abstract set - var k: Int abstract set - var k1: Int = 0; abstract set + var k: Int abstract set + var k1: Int = 0; abstract set - var l: Int abstract get abstract set - var l1: Int = 0; abstract get abstract set + var l: Int abstract get abstract set + var l1: Int = 0; abstract get abstract set - var n: Int abstract get abstract set(v: Int) {} + var n: Int abstract get abstract set(v: Int) {} } trait MyTrait { @@ -117,19 +117,19 @@ trait MyTrait { abstract fun j() {} //property accessors - var i: Int abstract get abstract set - var i1: Int = 0; abstract get abstract set + var i: Int abstract get abstract set + var i1: Int = 0; abstract get abstract set - var j: Int get() = i; abstract set - var j1: Int = 0; get() = i; abstract set + var j: Int get() = i; abstract set + var j1: Int = 0; get() = i; abstract set - var k: Int abstract set - var k1: Int = 0; abstract set + var k: Int abstract set + var k1: Int = 0; abstract set - var l: Int abstract get abstract set - var l1: Int = 0; abstract get abstract set + var l: Int abstract get abstract set + var l1: Int = 0; abstract get abstract set - var n: Int abstract get abstract set(v: Int) {} + var n: Int abstract get abstract set(v: Int) {} } enum class MyEnum() { @@ -161,19 +161,19 @@ enum class MyEnum() { abstract fun j() {} //property accessors - var i: Int abstract get abstract set - var i1: Int = 0; abstract get abstract set + var i: Int abstract get abstract set + var i1: Int = 0; abstract get abstract set - var j: Int get() = i; abstract set - var j1: Int = 0; get() = i; abstract set + var j: Int get() = i; abstract set + var j1: Int = 0; get() = i; abstract set - var k: Int abstract set - var k1: Int = 0; abstract set + var k: Int abstract set + var k1: Int = 0; abstract set - var l: Int abstract get abstract set - var l1: Int = 0; abstract get abstract set + var l: Int abstract get abstract set + var l1: Int = 0; abstract get abstract set - var n: Int abstract get abstract set(v: Int) {} + var n: Int abstract get abstract set(v: Int) {} } abstract enum class MyAbstractEnum() {} @@ -207,19 +207,19 @@ namespace MyNamespace { abstract fun j() {} //property accessors - var i: Int abstract get abstract set - var i1: Int = 0; abstract get abstract set + var i: Int abstract get abstract set + var i1: Int = 0; abstract get abstract set - var j: Int get() = i; abstract set - var j1: Int = 0; get() = i; abstract set + var j: Int get() = i; abstract set + var j1: Int = 0; get() = i; abstract set - var k: Int abstract set - var k1: Int = 0; abstract set + var k: Int abstract set + var k1: Int = 0; abstract set - var l: Int abstract get abstract set - var l1: Int = 0; abstract get abstract set + var l: Int abstract get abstract set + var l1: Int = 0; abstract get abstract set - var n: Int abstract get abstract set(v: Int) {} + var n: Int abstract get abstract set(v: Int) {} } //creating an instance diff --git a/idea/testData/checkerWithErrorTypes/full/BreakContinue.jet b/idea/testData/checkerWithErrorTypes/full/BreakContinue.jet index 2bf691799e0..1cecda9dae9 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 diff --git a/idea/testData/checkerWithErrorTypes/full/Constructors.jet b/idea/testData/checkerWithErrorTypes/full/Constructors.jet index 370fa759a3e..85a218569ac 100644 --- a/idea/testData/checkerWithErrorTypes/full/Constructors.jet +++ b/idea/testData/checkerWithErrorTypes/full/Constructors.jet @@ -22,7 +22,7 @@ class WithPC1(a : Int) { this(s : String) : this(1) {} - this(b : Char) : this("", 2) {} + this(b : Char) : this("", 2) {} this(b : Byte) : this(""), this(1) {} } diff --git a/idea/testData/checkerWithErrorTypes/full/ExtensionFunctions.jet b/idea/testData/checkerWithErrorTypes/full/ExtensionFunctions.jet index 54edfbaa527..d12496d9e8b 100644 --- a/idea/testData/checkerWithErrorTypes/full/ExtensionFunctions.jet +++ b/idea/testData/checkerWithErrorTypes/full/ExtensionFunctions.jet @@ -16,7 +16,7 @@ class A fun A.plus(a : Any) { 1.foo() - true.foo() + true.foo() 1 } @@ -55,10 +55,10 @@ namespace null_safety { val command = parse("") - command.foo + command.foo command.equals(null) - command?.equals(null) + command?.equals(null) command.equals1(null) command?.equals1(null) diff --git a/idea/testData/checkerWithErrorTypes/full/FunctionReturnTypes.jet b/idea/testData/checkerWithErrorTypes/full/FunctionReturnTypes.jet index 64012287566..646a38f5b89 100644 --- a/idea/testData/checkerWithErrorTypes/full/FunctionReturnTypes.jet +++ b/idea/testData/checkerWithErrorTypes/full/FunctionReturnTypes.jet @@ -164,3 +164,46 @@ fun f(): Int { } 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/checkerWithErrorTypes/full/IllegalModifiers.jet b/idea/testData/checkerWithErrorTypes/full/IllegalModifiers.jet index 9feae3696e1..a3585e341de 100644 --- a/idea/testData/checkerWithErrorTypes/full/IllegalModifiers.jet +++ b/idea/testData/checkerWithErrorTypes/full/IllegalModifiers.jet @@ -7,7 +7,7 @@ abstract class A() { open var r: String get - abstract protected set + abstract protected set } final trait T {} @@ -15,7 +15,7 @@ abstract class A() { class FinalClass() { open fun foo() {} val i: Int = 1 - open get(): Int = $i + open get(): Int = $i var j: Int = 1 - open set(v: Int) {} + open set(v: Int) {} } \ No newline at end of file diff --git a/idea/testData/checkerWithErrorTypes/full/NamespaceAsExpression.jet b/idea/testData/checkerWithErrorTypes/full/NamespaceAsExpression.jet index a7e2a3a78a7..de5e97fe5b8 100644 --- a/idea/testData/checkerWithErrorTypes/full/NamespaceAsExpression.jet +++ b/idea/testData/checkerWithErrorTypes/full/NamespaceAsExpression.jet @@ -4,5 +4,5 @@ namespace a { } -val x = a +val x = a val y2 = namespace diff --git a/idea/testData/checkerWithErrorTypes/full/NamespaceInExpressionPosition.jet b/idea/testData/checkerWithErrorTypes/full/NamespaceInExpressionPosition.jet new file mode 100644 index 00000000000..863f25630cc --- /dev/null +++ b/idea/testData/checkerWithErrorTypes/full/NamespaceInExpressionPosition.jet @@ -0,0 +1,11 @@ +namespace foo + +class X {} + +val s = java +val ss = System +val sss = X +val xs = java.lang +val xss = java.lang.System +val xsss = foo.X +val xssss = foo diff --git a/idea/testData/checkerWithErrorTypes/full/Properties.jet b/idea/testData/checkerWithErrorTypes/full/Properties.jet index 999ebc5173e..1b3ca0b8dee 100644 --- a/idea/testData/checkerWithErrorTypes/full/Properties.jet +++ b/idea/testData/checkerWithErrorTypes/full/Properties.jet @@ -25,4 +25,5 @@ class Test() { $b = $a a = $b } + public val i = 1 } \ No newline at end of file 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 + } +} 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 { diff --git a/idea/testData/checkerWithErrorTypes/full/When.jet b/idea/testData/checkerWithErrorTypes/full/When.jet index f8612546d1c..7f53fb38c9d 100644 --- a/idea/testData/checkerWithErrorTypes/full/When.jet +++ b/idea/testData/checkerWithErrorTypes/full/When.jet @@ -1,3 +1,5 @@ +fun Int.foo() : Boolean = true + fun foo() : Int { val s = "" val x = 1 @@ -17,7 +19,8 @@ fun foo() : Int { else => 1 } return when (x?:null) { - .equals(1) => 1 + .foo() => 1 + .equals(1) => 1 ?.equals(1).equals(2) => 1 } } diff --git a/idea/testData/checkerWithErrorTypes/full/infos/Autocasts.jet b/idea/testData/checkerWithErrorTypes/full/infos/Autocasts.jet index ff7066a34f5..a3cf2976f1f 100644 --- a/idea/testData/checkerWithErrorTypes/full/infos/Autocasts.jet +++ b/idea/testData/checkerWithErrorTypes/full/infos/Autocasts.jet @@ -47,11 +47,9 @@ class C() : A() { } fun f10(a : A?) { - if (a is B) { if (a is C) { a.bar(); } - } } fun f11(a : A?) { diff --git a/idea/testData/checkerWithErrorTypes/full/infos/PropertiesWithBackingFields.jet b/idea/testData/checkerWithErrorTypes/full/infos/PropertiesWithBackingFields.jet index 3f417b56418..9371df4b877 100644 --- a/idea/testData/checkerWithErrorTypes/full/infos/PropertiesWithBackingFields.jet +++ b/idea/testData/checkerWithErrorTypes/full/infos/PropertiesWithBackingFields.jet @@ -35,10 +35,12 @@ abstract class Test() { var v5 : Int get() = 1; set(x){$v5 = x} var v6 : Int get() = $v6 + 1; set(x){} - abstract val v7 : Int abstract get - abstract var v8 : Int abstract get abstract set - var v9 : Int abstract set - var v10 : Int abstract get + abstract val v7 : Int get + abstract var v8 : Int get set + var v9 : Int set + var v10 : Int get + abstract val v11 : Int abstract get + abstract var v12 : Int abstract get abstract set } diff --git a/idea/testData/checkerWithErrorTypes/full/regression/Jet67.jet b/idea/testData/checkerWithErrorTypes/full/regression/Jet67.jet index 7c2248a5f6a..94549ab8df9 100644 --- a/idea/testData/checkerWithErrorTypes/full/regression/Jet67.jet +++ b/idea/testData/checkerWithErrorTypes/full/regression/Jet67.jet @@ -1,4 +1,4 @@ abstract class XXX { - abstract val a : Int abstract get + abstract val a : Int get } diff --git a/idea/testData/checkerWithErrorTypes/quick/AutocastAmbiguitites.jet b/idea/testData/checkerWithErrorTypes/quick/AutocastAmbiguitites.jet new file mode 100644 index 00000000000..614374e9521 --- /dev/null +++ b/idea/testData/checkerWithErrorTypes/quick/AutocastAmbiguitites.jet @@ -0,0 +1,16 @@ +trait B { + fun bar() {} +} + +class C() { + fun bar() { + } +} + +fun test(a : Any?) { + if (a is B) { + if (a is C) { + a.bar(); + } + } +} diff --git a/idea/testData/checkerWithErrorTypes/quick/nullabilityAndAutoCasts/InfixCallNullability.jet b/idea/testData/checkerWithErrorTypes/quick/nullabilityAndAutoCasts/InfixCallNullability.jet new file mode 100644 index 00000000000..d27f6834a73 --- /dev/null +++ b/idea/testData/checkerWithErrorTypes/quick/nullabilityAndAutoCasts/InfixCallNullability.jet @@ -0,0 +1,41 @@ +class A() { + fun plus(i : Int) {} + fun minus() {} + fun contains(a : Any?) : Boolean = true +} + +fun A.div(i : Int) {} +fun A?.times(i : Int) {} + +fun test(x : Int?, a : A?) { + x.plus(1) + x?.plus(1) + x plus 1 + x + 1 + -x + x.minus() + x?.minus() + + a.plus(1) + a?.plus(1) + a plus 1 + a + 1 + -a + a.minus() + a?.minus() + + a.div(1) + a / 1 + a div 1 + a?.div(1) + + a.times(1) + a * 1 + a times 1 + a?.times(1) + + 1 in a + a contains 1 + a.contains(1) + a?.contains(1) +} diff --git a/idea/testData/checkerWithErrorTypes/quick/nullabilityAndAutoCasts/PreferExtensionsOnNullableReceiver.jet b/idea/testData/checkerWithErrorTypes/quick/nullabilityAndAutoCasts/PreferExtensionsOnNullableReceiver.jet new file mode 100644 index 00000000000..b841960b590 --- /dev/null +++ b/idea/testData/checkerWithErrorTypes/quick/nullabilityAndAutoCasts/PreferExtensionsOnNullableReceiver.jet @@ -0,0 +1,9 @@ +class Foo { + fun foo() {} +} + +fun Any?.foo() {} + +fun test(f : Foo?) { + f.foo() +} diff --git a/idea/testData/checkerWithErrorTypes/quick/nullabilityAndAutoCasts/ReceiverNullability.jet b/idea/testData/checkerWithErrorTypes/quick/nullabilityAndAutoCasts/ReceiverNullability.jet new file mode 100644 index 00000000000..0995252deff --- /dev/null +++ b/idea/testData/checkerWithErrorTypes/quick/nullabilityAndAutoCasts/ReceiverNullability.jet @@ -0,0 +1,44 @@ +class A { + fun foo() {} +} + +fun A.bar() {} +fun A?.buzz() {} + +fun test(a : A?) { + a.foo() // error + a.bar() // error + a.buzz() + + a?.foo() + a?.bar() + a?.buzz() // warning +} + +fun A.test() { + foo() + bar() + buzz() + + this.foo() + this.bar() + this.buzz() + + this?.foo() // warning + this?.bar() // warning + this?.buzz() // warning +} + +fun A?.test() { + foo() // error + bar() // error + buzz() + + this.foo() // error + this.bar() // error + this.buzz() + + this?.foo() + this?.bar() + this?.buzz() // warning +} diff --git a/idea/testData/codegen/classes/outerThis.jet b/idea/testData/codegen/classes/outerThis.jet index 61642ffa2e2..123fde68b46 100644 --- a/idea/testData/codegen/classes/outerThis.jet +++ b/idea/testData/codegen/classes/outerThis.jet @@ -3,7 +3,7 @@ class Outer() { val outer: Outer get() = this@Outer } - public val x = Inner() + public val x : Inner = Inner() } fun box() : String { diff --git a/idea/testData/codegen/classes/propertyDelegation.jet b/idea/testData/codegen/classes/propertyDelegation.jet index 0d030e74a8a..614c624f124 100644 --- a/idea/testData/codegen/classes/propertyDelegation.jet +++ b/idea/testData/codegen/classes/propertyDelegation.jet @@ -1,5 +1,5 @@ open class Base() { - public val plain = 239 + val plain = 239 public val read : Int get() = 239 diff --git a/idea/testData/codegen/classes/propertyInInitializer.jet b/idea/testData/codegen/classes/propertyInInitializer.jet index ed507f6278f..f6e84b15afd 100644 --- a/idea/testData/codegen/classes/propertyInInitializer.jet +++ b/idea/testData/codegen/classes/propertyInInitializer.jet @@ -1,5 +1,5 @@ class Outer() { - public val s = "xyzzy" + val s = "xyzzy" open class InnerBase(public val name: String) { } @@ -7,7 +7,7 @@ class Outer() { class InnerDerived(): InnerBase(s) { } - public val x = InnerDerived() + val x = InnerDerived() } fun box() : String { diff --git a/idea/testData/codegen/regressions/kt343.jet b/idea/testData/codegen/regressions/kt343.jet new file mode 100644 index 00000000000..49a8dc9c487 --- /dev/null +++ b/idea/testData/codegen/regressions/kt343.jet @@ -0,0 +1,24 @@ +import java.util.ArrayList + +fun launch(f : fun() : Unit) { + f() +} + +fun box(): String { + val list = ArrayList() + val foo : fun() : Unit = { + list.add(2) //first exception + } + foo() + + launch({ + list.add(3) + }) + + val bar = { + val x = 1 //second exception + } + bar() + + return if (list.size() == 2 && list.get(0) == 2 && list.get(1) == 3) "OK" else "fail" +} \ No newline at end of file diff --git a/idea/testData/quickfix/abstract/afterAbstractFunctionWithBody2.kt b/idea/testData/quickfix/abstract/afterAbstractFunctionWithBody2.kt new file mode 100644 index 00000000000..1712a56945f --- /dev/null +++ b/idea/testData/quickfix/abstract/afterAbstractFunctionWithBody2.kt @@ -0,0 +1,4 @@ +// "Remove function body" "true" +abstract class A() { + abstract fun foo() : Any +} diff --git a/idea/testData/quickfix/abstract/afterAbstractFunctionWithBody3.kt b/idea/testData/quickfix/abstract/afterAbstractFunctionWithBody3.kt new file mode 100644 index 00000000000..1712a56945f --- /dev/null +++ b/idea/testData/quickfix/abstract/afterAbstractFunctionWithBody3.kt @@ -0,0 +1,4 @@ +// "Remove function body" "true" +abstract class A() { + abstract fun foo() : Any +} diff --git a/idea/testData/quickfix/abstract/afterNonMemberAbstractAccessor.kt b/idea/testData/quickfix/abstract/afterNonMemberAbstractAccessor.kt deleted file mode 100644 index 9d9d46b6606..00000000000 --- a/idea/testData/quickfix/abstract/afterNonMemberAbstractAccessor.kt +++ /dev/null @@ -1,2 +0,0 @@ -// "Make 'get' not abstract" "true" -val i : Int = 0; get \ No newline at end of file diff --git a/idea/testData/quickfix/abstract/beforeAbstractFunctionWithBody2.kt b/idea/testData/quickfix/abstract/beforeAbstractFunctionWithBody2.kt new file mode 100644 index 00000000000..70a03c43058 --- /dev/null +++ b/idea/testData/quickfix/abstract/beforeAbstractFunctionWithBody2.kt @@ -0,0 +1,4 @@ +// "Remove function body" "true" +abstract class A() { + abstract fun foo() : Any { return "a" } +} diff --git a/idea/testData/quickfix/abstract/beforeAbstractFunctionWithBody3.kt b/idea/testData/quickfix/abstract/beforeAbstractFunctionWithBody3.kt new file mode 100644 index 00000000000..f15fe523b9c --- /dev/null +++ b/idea/testData/quickfix/abstract/beforeAbstractFunctionWithBody3.kt @@ -0,0 +1,4 @@ +// "Remove function body" "true" +abstract class A() { + abstract fun foo() : Any = 1 +} diff --git a/idea/testData/quickfix/abstract/beforeNonMemberAbstractAccessor.kt b/idea/testData/quickfix/abstract/beforeNonMemberAbstractAccessor.kt deleted file mode 100644 index 4eab8790a9e..00000000000 --- a/idea/testData/quickfix/abstract/beforeNonMemberAbstractAccessor.kt +++ /dev/null @@ -1,2 +0,0 @@ -// "Make 'get' not abstract" "true" -val i : Int = 0; abstract get \ No newline at end of file diff --git a/idea/testData/quickfix/modifiers/afterNonFinalAccessorOfFinalProperty1.kt b/idea/testData/quickfix/modifiers/afterNonFinalAccessorOfFinalProperty1.kt deleted file mode 100644 index 7ae88e4147a..00000000000 --- a/idea/testData/quickfix/modifiers/afterNonFinalAccessorOfFinalProperty1.kt +++ /dev/null @@ -1,5 +0,0 @@ -// "Make 'i' open" "true" -open class A() { - open val i: Int = 1 - open get(): Int = $i -} \ No newline at end of file diff --git a/idea/testData/quickfix/modifiers/afterNonFinalAccessorOfFinalProperty2.kt b/idea/testData/quickfix/modifiers/afterNonFinalAccessorOfFinalProperty2.kt deleted file mode 100644 index 62cf211cb44..00000000000 --- a/idea/testData/quickfix/modifiers/afterNonFinalAccessorOfFinalProperty2.kt +++ /dev/null @@ -1,5 +0,0 @@ -// "Make 'get' not open" "true" -open class A() { - val i: Int = 1 - get(): Int = $i -} \ No newline at end of file diff --git a/idea/testData/quickfix/modifiers/beforeNonFinalAccessorOfFinalProperty1.kt b/idea/testData/quickfix/modifiers/beforeNonFinalAccessorOfFinalProperty1.kt deleted file mode 100644 index da2f748ec26..00000000000 --- a/idea/testData/quickfix/modifiers/beforeNonFinalAccessorOfFinalProperty1.kt +++ /dev/null @@ -1,5 +0,0 @@ -// "Make 'i' open" "true" -open class A() { - val i: Int = 1 - open get(): Int = $i -} \ No newline at end of file diff --git a/idea/testData/quickfix/modifiers/beforeNonFinalAccessorOfFinalProperty2.kt b/idea/testData/quickfix/modifiers/beforeNonFinalAccessorOfFinalProperty2.kt deleted file mode 100644 index 868366c07ba..00000000000 --- a/idea/testData/quickfix/modifiers/beforeNonFinalAccessorOfFinalProperty2.kt +++ /dev/null @@ -1,5 +0,0 @@ -// "Make 'get' not open" "true" -open class A() { - val i: Int = 1 - open get(): Int = $i -} \ No newline at end of file diff --git a/idea/testData/quickfix/typeAddition/afterProtectedFunWithoutReturnType.kt b/idea/testData/quickfix/typeAddition/afterProtectedFunWithoutReturnType.kt new file mode 100644 index 00000000000..21bb2b8a61b --- /dev/null +++ b/idea/testData/quickfix/typeAddition/afterProtectedFunWithoutReturnType.kt @@ -0,0 +1,6 @@ +// "Add return type declaration" "true" +namespace a + +class A() { + protected fun foo() : Int = 1 +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeAddition/afterPublicFunWithoutReturnType.kt b/idea/testData/quickfix/typeAddition/afterPublicFunWithoutReturnType.kt new file mode 100644 index 00000000000..d6915a73b54 --- /dev/null +++ b/idea/testData/quickfix/typeAddition/afterPublicFunWithoutReturnType.kt @@ -0,0 +1,6 @@ +// "Add return type declaration" "true" +namespace a + +class A() { + public fun foo() : String = "a" +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeAddition/afterPublicValWithoutReturnType.kt b/idea/testData/quickfix/typeAddition/afterPublicValWithoutReturnType.kt new file mode 100644 index 00000000000..ff8817efeff --- /dev/null +++ b/idea/testData/quickfix/typeAddition/afterPublicValWithoutReturnType.kt @@ -0,0 +1,6 @@ +// "Add return type declaration" "true" +namespace a + +import java.util.List + +public val l : List? = java.util.Collections.emptyList() \ No newline at end of file diff --git a/idea/testData/quickfix/typeAddition/beforeInternalProtectedFunWithoutReturnType.kt b/idea/testData/quickfix/typeAddition/beforeInternalProtectedFunWithoutReturnType.kt new file mode 100644 index 00000000000..00fb6506546 --- /dev/null +++ b/idea/testData/quickfix/typeAddition/beforeInternalProtectedFunWithoutReturnType.kt @@ -0,0 +1,6 @@ +// "Add return type declaration" "false" +namespace a + +class A() { + internal protected fun foo() = 1 +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeAddition/beforeProtectedFunWithoutReturnType.kt b/idea/testData/quickfix/typeAddition/beforeProtectedFunWithoutReturnType.kt new file mode 100644 index 00000000000..5f8cb2d9cf1 --- /dev/null +++ b/idea/testData/quickfix/typeAddition/beforeProtectedFunWithoutReturnType.kt @@ -0,0 +1,6 @@ +// "Add return type declaration" "true" +namespace a + +class A() { + protected fun foo() = 1 +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeAddition/beforePublicFunWithoutBody.kt b/idea/testData/quickfix/typeAddition/beforePublicFunWithoutBody.kt new file mode 100644 index 00000000000..c031a9e7577 --- /dev/null +++ b/idea/testData/quickfix/typeAddition/beforePublicFunWithoutBody.kt @@ -0,0 +1,6 @@ +// "Add return type declaration" "false" +namespace a + +class A() { + public fun foo() +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeAddition/beforePublicFunWithoutReturnType.kt b/idea/testData/quickfix/typeAddition/beforePublicFunWithoutReturnType.kt new file mode 100644 index 00000000000..ad53bc3e9fd --- /dev/null +++ b/idea/testData/quickfix/typeAddition/beforePublicFunWithoutReturnType.kt @@ -0,0 +1,6 @@ +// "Add return type declaration" "true" +namespace a + +class A() { + public fun foo() = "a" +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeAddition/beforePublicValWithoutReturnType.kt b/idea/testData/quickfix/typeAddition/beforePublicValWithoutReturnType.kt new file mode 100644 index 00000000000..a162305a91c --- /dev/null +++ b/idea/testData/quickfix/typeAddition/beforePublicValWithoutReturnType.kt @@ -0,0 +1,4 @@ +// "Add return type declaration" "true" +namespace a + +public val l = java.util.Collections.emptyList() \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java b/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java index dcd5e4d9783..a7aa2572f54 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java @@ -58,4 +58,46 @@ public class ArrayGenTest extends CodegenTestCase { System.out.println(invoke.getClass()); assertTrue(invoke instanceof Integer); } + + public void testIterator () throws Exception { + loadText("fun box() { val x = Array(5, { it } ).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } + + public void testPrimitiveIterator () throws Exception { + loadText("fun box() { val x = ByteArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } + + public void testLongIterator () throws Exception { + loadText("fun box() { val x = LongArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } + + public void testCharIterator () throws Exception { + loadText("fun box() { val x = CharArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } + + public void testArrayIndices () throws Exception { + loadText("fun box() { val x = Array(5, {it}).indices.iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } + + public void testCharIndices () throws Exception { + loadText("fun box() { val x = CharArray(5).indices.iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + foo.invoke(null); + } } diff --git a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java index 4e6f7802f56..72a131c61c6 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -178,4 +178,16 @@ 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()); + } + + public void testKt343 () throws Exception { + blackBoxFile("regressions/kt343.jet"); + System.out.println(generateToText()); + } } 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/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java b/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java index fa54529a99f..cd81cc54e01 100644 --- a/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java @@ -34,7 +34,7 @@ public class PropertyGenTest extends CodegenTestCase { } public void testPublicVar() throws Exception { - loadText("class PublicVar() { public var foo = 0; }"); + loadText("class PublicVar() { public var foo : Int = 0; }"); final Class aClass = loadImplementationClass(generateClassesInFile(), "PublicVar"); final Object instance = aClass.newInstance(); Method setter = findMethodByName(aClass, "setFoo"); @@ -44,7 +44,7 @@ public class PropertyGenTest extends CodegenTestCase { } public void testAccessorsInInterface() { - loadText("class AccessorsInInterface() { public var foo = 0; }"); + loadText("class AccessorsInInterface() { public var foo : Int = 0; }"); final Class aClass = loadClass("AccessorsInInterface", generateClassesInFile()); assertNotNull(findMethodByName(aClass, "getFoo")); assertNotNull(findMethodByName(aClass, "setFoo")); @@ -108,7 +108,7 @@ public class PropertyGenTest extends CodegenTestCase { } public void testInitializersForNamespaceProperties() throws Exception { - loadText("public val x = System.currentTimeMillis()"); + loadText("val x = System.currentTimeMillis()"); final Method method = generateFunction("getX"); assertIsCurrentTime((Long) method.invoke(null)); } @@ -136,7 +136,7 @@ public class PropertyGenTest extends CodegenTestCase { } public void testKt160() throws Exception { - loadText("public val s = java.lang.Double.toString(1.0)"); + loadText("internal val s = java.lang.Double.toString(1.0)"); final Method method = generateFunction("getS"); assertEquals(method.invoke(null), "1.0"); } diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/TypeAdditionFixTests.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/TypeAdditionFixTests.java index 42c100016f6..b9154602f09 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/TypeAdditionFixTests.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/TypeAdditionFixTests.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.plugin.quickfix; import com.intellij.codeInsight.daemon.quickFix.LightQuickFixTestCase; +import com.intellij.openapi.projectRoots.Sdk; import org.jetbrains.jet.JetTestCaseBase; /** @@ -21,5 +22,10 @@ public class TypeAdditionFixTests extends LightQuickFixTestCase { protected String getTestDataPath() { return JetTestCaseBase.getTestDataPathBase(); } + + @Override + protected Sdk getProjectJDK() { + return JetTestCaseBase.jdkFromIdeaHome(); + } } diff --git a/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java b/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java index 309b9e984bd..8d275884991 100644 --- a/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java +++ b/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java @@ -12,12 +12,13 @@ import junit.framework.Test; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.JetTestCaseBase; import org.jetbrains.jet.lang.JetSemanticServices; -import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.resolve.BindingTraceContext; -import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResult; +import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.lang.types.expressions.JetTypeInferrerServices; import org.jetbrains.jet.parsing.JetParsingTest; import java.io.File; @@ -105,16 +106,16 @@ 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); + JetTypeInferrerServices typeInferrerServices = JetSemanticServices.createSemanticServices(getProject()).getTypeInferrerServices(new BindingTraceContext()); - OverloadResolutionResult functions = typeInferrerServices.getCallResolver().resolveExactSignature( + OverloadResolutionResults functions = typeInferrerServices.getCallResolver().resolveExactSignature( classDescriptor.getMemberScope(typeArguments), ReceiverDescriptor.NO_RECEIVER, name, parameterTypeList); - for (FunctionDescriptor function : functions.getDescriptors()) { - List unsubstitutedValueParameters = function.getValueParameters(); + for (ResolvedCall resolvedCall : functions.getResults()) { + List unsubstitutedValueParameters = resolvedCall.getResultingDescriptor().getValueParameters(); for (int i = 0, unsubstitutedValueParametersSize = unsubstitutedValueParameters.size(); i < unsubstitutedValueParametersSize; i++) { ValueParameterDescriptor unsubstitutedValueParameter = unsubstitutedValueParameters.get(i); if (unsubstitutedValueParameter.getOutType().equals(parameterType[i])) { - return function; + return resolvedCall.getResultingDescriptor(); } } } diff --git a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java index 1903d2b13f1..54aeedef944 100644 --- a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java +++ b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java @@ -10,7 +10,6 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetTestCaseBase; import org.jetbrains.jet.JetTestUtils; 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.psi.*; @@ -21,6 +20,7 @@ import org.jetbrains.jet.lang.resolve.scopes.*; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.lang.types.expressions.JetTypeInferrer; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.parsing.JetParsingTest; @@ -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); } 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/IntRange.java b/stdlib/src/jet/IntRange.java index dc538cddc4b..abeb2a0f696 100644 --- a/stdlib/src/jet/IntRange.java +++ b/stdlib/src/jet/IntRange.java @@ -1,28 +1,99 @@ package jet; -public class IntRange implements Range { - private final int startValue; - private final int endValue; +import jet.typeinfo.TypeInfo; - public IntRange(int startValue, int endValue) { - this.startValue = startValue; - this.endValue = endValue; +public final class IntRange implements Range, Iterable, JetObject { + private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(IntRange.class, false); + + private final int start; + private final int count; + + public IntRange(int startValue, int count) { + this.start = startValue; + this.count = count; + } + + public IntRange(int startValue, int count, boolean reversed) { + this(startValue, reversed ? -count : count); } @Override public boolean contains(Integer item) { if (item == null) return false; - if (startValue <= endValue) { - return item >= startValue && item <= endValue; + if (count >= 0) { + return item >= start && item < start + count; } - return item <= startValue && item >= endValue; + return item <= start && item > start + count; } - public int getStartValue() { - return startValue; + public int getStart() { + return start; } - public int getEndValue() { - return endValue; + public int getEnd() { + return start+count-1; + } + + public int getSize() { + return count < 0 ? -count : count; + } + + @Override + public Iterator iterator() { + return new MyIterator(start, count); + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + + public static IntRange count(int length) { + return new IntRange(0, length); + } + + public static IntRange rangeTo(int from, int to) { + if(from > to) { + return new IntRange(to, from-to+1, true); + } + else { + return new IntRange(from, to-from+1); + } + } + + private static class MyIterator implements Iterator { + private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(MyIterator.class, false); + + private int cur; + private int count; + + private final boolean reversed; + + public MyIterator(int startValue, int count) { + cur = startValue; + reversed = count < 0; + this.count = reversed ? -count : count; + } + + @Override + public boolean hasNext() { + return count > 0; + } + + @Override + public Integer next() { + count--; + if(reversed) { + return cur--; + } + else { + return cur++; + } + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } } } diff --git a/stdlib/src/jet/LongRange.java b/stdlib/src/jet/LongRange.java new file mode 100644 index 00000000000..7932f7d0b5d --- /dev/null +++ b/stdlib/src/jet/LongRange.java @@ -0,0 +1,99 @@ +package jet; + +import jet.typeinfo.TypeInfo; + +public final class LongRange implements Range, Iterable, JetObject { + private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(IntRange.class, false); + + private final long start; + private final long count; + + public LongRange(long startValue, long count) { + this.start = startValue; + this.count = count; + } + + public LongRange(long startValue, long count, boolean reversed) { + this(startValue, reversed ? -count : count); + } + + @Override + public boolean contains(Long item) { + if (item == null) return false; + if (count >= 0) { + return item >= start && item < start + count; + } + return item <= start && item > start + count; + } + + public long getStart() { + return start; + } + + public long getEnd() { + return start+count-1; + } + + public long getSize() { + return count < 0 ? -count : count; + } + + @Override + public Iterator iterator() { + return new MyIterator(start, count); + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + + public static IntRange count(int length) { + return new IntRange(0, length); + } + + public static IntRange rangeTo(int from, int to) { + if(from > to) { + return new IntRange(to, from-to+1, true); + } + else { + return new IntRange(from, to-from+1); + } + } + + private static class MyIterator implements Iterator { + private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(MyIterator.class, false); + + private long cur; + private long count; + + private final boolean reversed; + + public MyIterator(long startValue, long count) { + cur = startValue; + reversed = count < 0; + this.count = reversed ? -count : count; + } + + @Override + public boolean hasNext() { + return count > 0; + } + + @Override + public Long next() { + count--; + if(reversed) { + return cur--; + } + else { + return cur++; + } + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } + } +} diff --git a/stdlib/src/jet/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/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" + + ""); + } + } +} 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);