From 496549cab81f055b4dbb84ab6daf0e379f2ab005 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 30 Aug 2011 19:02:18 +0400 Subject: [PATCH] this() calls supported properties integrated --- .../codegen/ImplementationBodyCodegen.java | 2 +- .../lang/descriptors/CallableDescriptor.java | 36 + .../ConstructorDescriptorImpl.java | 2 +- .../lang/descriptors/FunctionDescriptor.java | 21 +- .../descriptors/FunctionDescriptorImpl.java | 2 +- .../descriptors/FunctionDescriptorUtil.java | 55 +- .../lang/descriptors/PropertyDescriptor.java | 11 +- .../descriptors/PropertyGetterDescriptor.java | 2 +- .../descriptors/PropertySetterDescriptor.java | 2 +- .../lang/descriptors/VariableDescriptor.java | 2 +- .../descriptors/VariableDescriptorImpl.java | 37 + .../jet/lang/resolve/DescriptorUtils.java | 59 ++ .../jet/lang/resolve/TopDownAnalyzer.java | 16 +- .../calls}/CallResolver.java | 792 +++++++++--------- .../calls/OverloadingConflictResolver.java | 122 +++ .../lang/resolve/calls/ResolutionTask.java | 71 ++ .../lang/resolve/calls/TaskPrioritizer.java | 108 +++ .../lang/resolve/calls/TracingStrategy.java | 22 + .../ValueArgumentsToParametersMapper.java | 154 ++++ .../jetbrains/jet/lang/types/CallMaker.java | 12 +- .../jetbrains/jet/lang/types/ErrorUtils.java | 2 +- .../jet/lang/types/JetTypeChecker.java | 6 +- .../jet/lang/types/JetTypeInferrer.java | 135 ++- .../annotations/JetLineMarkerProvider.java | 2 +- .../jet/resolve/DescriptorRenderer.java | 2 +- 25 files changed, 1125 insertions(+), 550 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/lang/descriptors/CallableDescriptor.java rename idea/src/org/jetbrains/jet/lang/{types => resolve/calls}/CallResolver.java (55%) create mode 100644 idea/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java create mode 100644 idea/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java create mode 100644 idea/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java create mode 100644 idea/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java create mode 100644 idea/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java diff --git a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 1b334c29722..2d9caa35205 100644 --- a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -216,7 +216,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { HashSet overridden = new HashSet(); for (JetDeclaration declaration : myClass.getDeclarations()) { if (declaration instanceof JetFunction) { - overridden.addAll(state.getBindingContext().get(BindingContext.FUNCTION, (JetNamedFunction) declaration).getOverriddenFunctions()); + overridden.addAll(state.getBindingContext().get(BindingContext.FUNCTION, (JetNamedFunction) declaration).getOverriddenDescriptors()); } } diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/CallableDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/CallableDescriptor.java new file mode 100644 index 00000000000..d263169649a --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/descriptors/CallableDescriptor.java @@ -0,0 +1,36 @@ +package org.jetbrains.jet.lang.descriptors; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeSubstitutor; + +import java.util.List; +import java.util.Set; + +/** +* @author abreslav +*/ +public interface CallableDescriptor extends DeclarationDescriptor { + @Nullable + JetType getReceiverType(); + + @NotNull + List getTypeParameters(); + + @NotNull + JetType getReturnType(); + + @NotNull + @Override + CallableDescriptor getOriginal(); + + @Override + CallableDescriptor substitute(TypeSubstitutor substitutor); + + @NotNull + List getValueParameters(); + + @NotNull + Set getOverriddenDescriptors(); +} diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/ConstructorDescriptorImpl.java b/idea/src/org/jetbrains/jet/lang/descriptors/ConstructorDescriptorImpl.java index 80c677a89a7..511de6d8fcf 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/ConstructorDescriptorImpl.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/ConstructorDescriptorImpl.java @@ -62,7 +62,7 @@ public class ConstructorDescriptorImpl extends FunctionDescriptorImpl implements @NotNull @Override - public Set getOverriddenFunctions() { + public Set getOverriddenDescriptors() { return Collections.emptySet(); } diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptor.java index 48c2622d412..6059b5bda63 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptor.java @@ -1,39 +1,26 @@ package org.jetbrains.jet.lang.descriptors; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeSubstitutor; -import java.util.List; import java.util.Set; /** * @author abreslav */ -public interface FunctionDescriptor extends DeclarationDescriptor { +public interface FunctionDescriptor extends CallableDescriptor { @Override @NotNull DeclarationDescriptor getContainingDeclaration(); - @Nullable - JetType getReceiverType(); - - @NotNull - List getTypeParameters(); - - @NotNull - List getValueParameters(); - - @NotNull - JetType getReturnType(); - @NotNull + @Override FunctionDescriptor getOriginal(); @Override FunctionDescriptor substitute(TypeSubstitutor substitutor); + @Override @NotNull - Set getOverriddenFunctions(); + Set getOverriddenDescriptors(); } diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java b/idea/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java index 4dbe72f0f88..611cc25d2d7 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java @@ -65,7 +65,7 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements @NotNull @Override - public Set getOverriddenFunctions() { + public Set getOverriddenDescriptors() { return overriddenFunctions; } diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java b/idea/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java index bfb0fc48ece..1fa41b06c43 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java @@ -48,7 +48,7 @@ public class FunctionDescriptorUtil { return unsubstitutedValueParameters.size(); } - private static Map createSubstitutionContext(@NotNull FunctionDescriptor functionDescriptor, List typeArguments) { + public static Map createSubstitutionContext(@NotNull FunctionDescriptor functionDescriptor, List typeArguments) { if (functionDescriptor.getTypeParameters().isEmpty()) return Collections.emptyMap(); Map result = new HashMap(); @@ -112,59 +112,6 @@ public class FunctionDescriptorUtil { return parameterScope; } - @NotNull - public static FunctionDescriptor substituteBounds(@NotNull FunctionDescriptor functionDescriptor) { - final List typeParameters = functionDescriptor.getTypeParameters(); - if (typeParameters.isEmpty()) return functionDescriptor; - final Map typeConstructors = Maps.newHashMap(); - for (TypeParameterDescriptor typeParameter : typeParameters) { - typeConstructors.put(typeParameter.getTypeConstructor(), typeParameter); - } - return functionDescriptor.substitute(new TypeSubstitutor(TypeSubstitution.EMPTY) { - @Override - public boolean inRange(@NotNull TypeConstructor typeConstructor) { - return typeConstructors.containsKey(typeConstructor); - } - - @Override - public boolean isEmpty() { - return typeParameters.isEmpty(); - } - - @NotNull - @Override - public TypeSubstitution getSubstitution() { - throw new UnsupportedOperationException(); - } - - @NotNull - @Override - public JetType safeSubstitute(@NotNull JetType type, @NotNull Variance howThisTypeIsUsed) { - JetType substituted = substitute(type, howThisTypeIsUsed); - if (substituted == null) { - return ErrorUtils.createErrorType("Substitution failed"); - } - return substituted; - } - - @Override - public JetType substitute(@NotNull JetType type, @NotNull Variance howThisTypeIsUsed) { - TypeParameterDescriptor typeParameterDescriptor = typeConstructors.get(type.getConstructor()); - if (typeParameterDescriptor != null) { - switch (howThisTypeIsUsed) { - case INVARIANT: - return type; - case IN_VARIANCE: - throw new UnsupportedOperationException(); // TODO : lower bounds - case OUT_VARIANCE: - return typeParameterDescriptor.getDefaultType(); - } - } - return super.substitute(type, howThisTypeIsUsed); - } - }); - } - public static class OverrideCompatibilityInfo { private static final OverrideCompatibilityInfo SUCCESS = new OverrideCompatibilityInfo(false, "SUCCESS"); diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java index 552f257ade8..ccd946bb296 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java @@ -78,7 +78,8 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Member } @NotNull - public List getTypeParemeters() { + @Override + public List getTypeParameters() { return typeParemeters; } @@ -87,6 +88,12 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Member return receiverType; } + @NotNull + @Override + public JetType getReturnType() { + return getOutType(); + } + public boolean isVar() { return isVar; @@ -110,7 +117,7 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Member @NotNull @Override - public VariableDescriptor substitute(TypeSubstitutor substitutor) { + public PropertyDescriptor substitute(TypeSubstitutor substitutor) { JetType originalInType = getInType(); JetType inType = originalInType == null ? null : substitutor.substitute(originalInType, Variance.IN_VARIANCE); JetType originalOutType = getOutType(); diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java index e434436c598..f1efa53d480 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java @@ -24,7 +24,7 @@ public class PropertyGetterDescriptor extends PropertyAccessorDescriptor { @NotNull @Override - public Set getOverriddenFunctions() { + public Set getOverriddenDescriptors() { return overriddenGetters; } diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java index 2e31121f278..323719eb5c2 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java @@ -33,7 +33,7 @@ public class PropertySetterDescriptor extends PropertyAccessorDescriptor { @NotNull @Override - public Set getOverriddenFunctions() { + public Set getOverriddenDescriptors() { return overriddenSetters; } diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/VariableDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/VariableDescriptor.java index 1d942a63393..fc883d59508 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/VariableDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/VariableDescriptor.java @@ -8,7 +8,7 @@ import org.jetbrains.jet.lang.types.TypeSubstitutor; /** * @author abreslav */ -public interface VariableDescriptor extends DeclarationDescriptor { +public interface VariableDescriptor extends CallableDescriptor { /** * @return null for write-only variables (i.e. properties), variable value type otherwise */ diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java b/idea/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java index d4b01df9815..3807447cddc 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java @@ -5,7 +5,9 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.types.JetType; +import java.util.Collections; import java.util.List; +import java.util.Set; /** * @author abreslav @@ -44,4 +46,39 @@ public abstract class VariableDescriptorImpl extends DeclarationDescriptorImpl i protected void setOutType(JetType outType) { this.outType = outType; } + + @Override + @NotNull + public VariableDescriptor getOriginal() { + return (VariableDescriptor) super.getOriginal(); + } + + @NotNull + @Override + public List getValueParameters() { + return Collections.emptyList(); + } + + @NotNull + @Override + public Set getOverriddenDescriptors() { + return Collections.emptySet(); + } + + @NotNull + @Override + public List getTypeParameters() { + return Collections.emptyList(); + } + + @Override + public JetType getReceiverType() { + return null; + } + + @NotNull + @Override + public JetType getReturnType() { + return getOutType(); + } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java b/idea/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java index 3fdd90e670e..1aaeaecf64f 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java @@ -1,7 +1,12 @@ package org.jetbrains.jet.lang.resolve; +import com.google.common.collect.Maps; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.types.*; + +import java.util.List; +import java.util.Map; /** * @author abreslav @@ -30,4 +35,58 @@ public class DescriptorUtils { } }, null); } + + @NotNull + public static Descriptor substituteBounds(@NotNull Descriptor functionDescriptor) { + final List typeParameters = functionDescriptor.getTypeParameters(); + if (typeParameters.isEmpty()) return functionDescriptor; + final Map typeConstructors = Maps.newHashMap(); + for (TypeParameterDescriptor typeParameter : typeParameters) { + typeConstructors.put(typeParameter.getTypeConstructor(), typeParameter); + } + //noinspection unchecked + return (Descriptor) functionDescriptor.substitute(new TypeSubstitutor(TypeSubstitutor.TypeSubstitution.EMPTY) { + @Override + public boolean inRange(@NotNull TypeConstructor typeConstructor) { + return typeConstructors.containsKey(typeConstructor); + } + + @Override + public boolean isEmpty() { + return typeParameters.isEmpty(); + } + + @NotNull + @Override + public TypeSubstitution getSubstitution() { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public JetType safeSubstitute(@NotNull JetType type, @NotNull Variance howThisTypeIsUsed) { + JetType substituted = substitute(type, howThisTypeIsUsed); + if (substituted == null) { + return ErrorUtils.createErrorType("Substitution failed"); + } + return substituted; + } + + @Override + public JetType substitute(@NotNull JetType type, @NotNull Variance howThisTypeIsUsed) { + TypeParameterDescriptor typeParameterDescriptor = typeConstructors.get(type.getConstructor()); + if (typeParameterDescriptor != null) { + switch (howThisTypeIsUsed) { + case INVARIANT: + return type; + case IN_VARIANCE: + throw new UnsupportedOperationException(); // TODO : lower bounds + case OUT_VARIANCE: + return typeParameterDescriptor.getDefaultType(); + } + } + return super.substitute(type, howThisTypeIsUsed); + } + }); + } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 57006c0d4e9..2a4236d5769 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -580,7 +580,7 @@ public class TopDownAnalyzer { JetTypeReference typeReference = call.getTypeReference(); if (typeReference != null) { if (descriptor.getUnsubstitutedPrimaryConstructor() != null) { - typeInferrer.getCallResolver().resolveCall(scopeForConstructor, null, call, NO_EXPECTED_TYPE); + typeInferrer.getCallResolver().resolveCall(trace, scopeForConstructor, null, call, NO_EXPECTED_TYPE); } else { JetValueArgumentList valueArgumentList = call.getValueArgumentList(); @@ -685,7 +685,7 @@ public class TopDownAnalyzer { public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) { JetTypeReference typeReference = call.getTypeReference(); if (typeReference != null) { - typeInferrerForInitializers.getCallResolver().resolveCall(functionInnerScope, null, call, NO_EXPECTED_TYPE); + typeInferrerForInitializers.getCallResolver().resolveCall(trace, functionInnerScope, null, call, NO_EXPECTED_TYPE); } } @@ -693,14 +693,16 @@ public class TopDownAnalyzer { public void visitDelegationToThisCall(JetDelegatorToThisCall call) { // TODO : check that there's no recursion in this() calls // TODO : check: if a this() call is present, no other initializers are allowed -// ClassDescriptor classDescriptor = descriptor.getContainingDeclaration(); -// typeInferrerForInitializers.checkClassConstructorCall( -// functionInnerScope, + ClassDescriptor classDescriptor = descriptor.getContainingDeclaration(); + + typeInferrerForInitializers.getCallResolver().resolveCall(trace, + functionInnerScope, + null, call, NO_EXPECTED_TYPE); // call.getThisReference(), // classDescriptor, // classDescriptor.getDefaultType(), // call); - trace.getErrorHandler().genericError(call.getNode(), "this-calls are not supported"); +// trace.getErrorHandler().genericError(call.getNode(), "this-calls are not supported"); } @Override @@ -805,7 +807,7 @@ public class TopDownAnalyzer { private JetScope getPropertyDeclarationInnerScope(@NotNull JetScope outerScope, @NotNull PropertyDescriptor propertyDescriptor) { WritableScopeImpl result = new WritableScopeImpl(outerScope, propertyDescriptor, trace.getErrorHandler()).setDebugName("Property declaration inner scope"); - for (TypeParameterDescriptor typeParameterDescriptor : propertyDescriptor.getTypeParemeters()) { + for (TypeParameterDescriptor typeParameterDescriptor : propertyDescriptor.getTypeParameters()) { result.addTypeParameterDescriptor(typeParameterDescriptor); } JetType receiverType = propertyDescriptor.getReceiverType(); diff --git a/idea/src/org/jetbrains/jet/lang/types/CallResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java similarity index 55% rename from idea/src/org/jetbrains/jet/lang/types/CallResolver.java rename to idea/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index e7d130ab149..ae9f7a0508c 100644 --- a/idea/src/org/jetbrains/jet/lang/types/CallResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -1,4 +1,4 @@ -package org.jetbrains.jet.lang.types; +package org.jetbrains.jet.lang.resolve.calls; import com.google.common.base.Function; import com.google.common.base.Functions; @@ -12,6 +12,7 @@ import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.*; +import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.inference.ConstraintSystem; import org.jetbrains.jet.resolve.DescriptorRenderer; @@ -25,100 +26,50 @@ import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE; */ public class CallResolver { - private static class ResolutionTask { - private final Collection candidates; - private final JetType receiverType; - private final List typeArguments; - private final List valueArguments; - private final List functionLiteralArguments; - - protected ResolutionTask( - @NotNull Collection candidates, - @Nullable JetType receiverType, - @NotNull List typeArguments, - @NotNull List valueArguments, - @NotNull List functionLiteralArguments) { - this.candidates = candidates; - this.receiverType = receiverType; - this.typeArguments = typeArguments; - this.valueArguments = valueArguments; - this.functionLiteralArguments = functionLiteralArguments; - } - - public ResolutionTask( - @NotNull Collection candidates, - @Nullable JetType receiverType, - @NotNull Call call) { - this(candidates, receiverType, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments()); - } - - @NotNull - public Collection getCandidates() { - return candidates; - } - - @Nullable - public JetType getReceiverType() { - return receiverType; - } - - @NotNull - public List getTypeArguments() { - return typeArguments; - } - - @NotNull - public List getValueArguments() { - return valueArguments; - } - - @NotNull - public List getFunctionLiteralArguments() { - return functionLiteralArguments; - } - } - - private interface TracingStrategy { - void bindFunctionReference(@NotNull BindingTrace trace, @NotNull FunctionDescriptor functionDescriptor); - - void reportOverallResolutionError(@NotNull BindingTrace trace, @NotNull String message); - - void reportWrongTypeArguments(@NotNull BindingTrace trace, @NotNull String message); - - void reportWrongValueArguments(@NotNull BindingTrace trace, @NotNull String message); - - void reportUnresolvedFunctionReference(@NotNull BindingTrace trace); - - void reportErrorOnFunctionReference(BindingTrace trace, String message); - } - - private final BindingTrace trace; +// private final BindingTrace trace; private final TypeResolver typeResolver; private final JetTypeInferrer typeInferrer; private final JetSemanticServices semanticServices; private final ClassDescriptorResolver classDescriptorResolver; + private final OverloadingConflictResolver overloadingConflictResolver; public CallResolver(JetSemanticServices semanticServices, BindingTrace trace, JetTypeInferrer typeInferrer) { - this.trace = trace; +// this.trace = trace; this.typeInferrer = typeInferrer; this.typeResolver = new TypeResolver(semanticServices, trace, true); this.classDescriptorResolver = semanticServices.getClassDescriptorResolver(trace); this.semanticServices = semanticServices; + this.overloadingConflictResolver = new OverloadingConflictResolver(semanticServices); } + @Nullable + public VariableDescriptor resolveSimpleProperty( + @NotNull BindingTrace trace, + @NotNull JetScope scope, + @Nullable JetType receiverType, + @NotNull final JetSimpleNameExpression nameExpression, + @NotNull JetType expectedType) { + Call call = CallMaker.makePropertyCall(nameExpression); + List> prioritizedTasks = PROPERTY_TASK_PRIORITIZER.computePrioritizedTasks(scope, receiverType, call, nameExpression.getReferencedName()); + return resolveCallToDescriptor(trace, scope, call, nameExpression.getNode(), expectedType, prioritizedTasks, nameExpression); + } + + @Nullable public JetType resolveCall( + @NotNull BindingTrace trace, @NotNull JetScope scope, @Nullable JetType receiverType, @NotNull JetCallElement call, @NotNull JetType expectedType ) { - FunctionDescriptor functionDescriptor = resolveSimpleCallToFunctionDescriptor(scope, receiverType, call, expectedType); + FunctionDescriptor functionDescriptor = resolveSimpleCallToFunctionDescriptor(trace, scope, receiverType, call, expectedType); return functionDescriptor == null ? null : functionDescriptor.getReturnType(); } @Nullable public FunctionDescriptor resolveCallWithGivenName( + @NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull final Call call, @NotNull final JetReferenceExpression functionReference, @@ -127,18 +78,19 @@ public class CallResolver { @NotNull JetType expectedType) { // TODO : autocasts // TODO : nullability - List tasks = computePrioritizedTasks(scope, receiverType, call, name); - return resolveCallToFunctionDescriptor(scope, call, functionReference.getNode(), expectedType, tasks, functionReference); + List> tasks = FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, receiverType, call, name); + return resolveCallToDescriptor(trace, scope, call, functionReference.getNode(), expectedType, tasks, functionReference); } @Nullable public FunctionDescriptor resolveSimpleCallToFunctionDescriptor( + @NotNull BindingTrace trace, @NotNull JetScope scope, @Nullable JetType receiverType, @NotNull final JetCallElement call, @NotNull JetType expectedType ) { - List prioritizedTasks; + List> prioritizedTasks; JetExpression calleeExpression = call.getCalleeExpression(); final JetReferenceExpression functionReference; @@ -149,7 +101,7 @@ public class CallResolver { String name = expression.getReferencedName(); if (name == null) return null; - prioritizedTasks = computePrioritizedTasks(scope, receiverType, call, name); + prioritizedTasks = FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, receiverType, call, name); } else if (calleeExpression instanceof JetConstructorCalleeExpression) { assert receiverType == null; @@ -162,96 +114,58 @@ public class CallResolver { return null; // No type there } JetTypeReference typeReference = expression.getTypeReference(); + assert typeReference != null; JetType constructedType = typeResolver.resolveType(scope, typeReference); DeclarationDescriptor declarationDescriptor = constructedType.getConstructor().getDeclarationDescriptor(); if (declarationDescriptor instanceof ClassDescriptor) { ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; - Set members = classDescriptor.getConstructors().getFunctionDescriptors(); - if (members.isEmpty()) { + Set constructors = classDescriptor.getConstructors().getFunctionDescriptors(); + if (constructors.isEmpty()) { trace.getErrorHandler().genericError(call.getValueArgumentList().getNode(), "This class does not have a constructor"); return null; } - addTask(prioritizedTasks, null, call, members); + prioritizedTasks.add(new ResolutionTask(constructors, null, call)); } else { trace.getErrorHandler().genericError(calleeExpression.getNode(), "Not a class"); return null; } + } else if (calleeExpression instanceof JetThisReferenceExpression) { + functionReference = (JetThisReferenceExpression) calleeExpression; + DeclarationDescriptor containingDeclaration = scope.getContainingDeclaration(); + assert containingDeclaration instanceof ClassDescriptor; + ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; + + + Set constructors = classDescriptor.getConstructors().getFunctionDescriptors(); + if (constructors.isEmpty()) { + trace.getErrorHandler().genericError(call.getValueArgumentList().getNode(), "This class does not have a constructor"); + return null; + } + prioritizedTasks = Collections.singletonList(new ResolutionTask(constructors, null, call)); } else { throw new UnsupportedOperationException("Type argument inference not implemented for " + call); } - return resolveCallToFunctionDescriptor(scope, call, call.getNode(), expectedType, prioritizedTasks, functionReference); + return resolveCallToDescriptor(trace, scope, call, call.getNode(), expectedType, prioritizedTasks, functionReference); } - private List computePrioritizedTasks(JetScope scope, JetType receiverType, Call call, String name) { - List result = Lists.newArrayList(); - if (receiverType != null) { - Collection extensionFunctions = Sets.newLinkedHashSet(scope.getFunctionGroup(name).getFunctionDescriptors()); - for (Iterator iterator = extensionFunctions.iterator(); iterator.hasNext(); ) { - FunctionDescriptor functionDescriptor = iterator.next(); - if (functionDescriptor.getReceiverType() == null) { - iterator.remove(); - } - } - List nonlocals = Lists.newArrayList(); - List locals = Lists.newArrayList(); - splitLexicallyLocalDescriptors(extensionFunctions, scope.getContainingDeclaration(), locals, nonlocals); - Set members = Sets.newHashSet(receiverType.getMemberScope().getFunctionGroup(name).getFunctionDescriptors()); - addConstrtuctors(receiverType.getMemberScope(), name, members); - addTask(result, receiverType, call, locals); - addTask(result, null, call, members); - addTask(result, receiverType, call, nonlocals); - } - else { - Collection functions = Sets.newLinkedHashSet(scope.getFunctionGroup(name).getFunctionDescriptors()); - for (Iterator iterator = functions.iterator(); iterator.hasNext(); ) { - FunctionDescriptor functionDescriptor = iterator.next(); - if (functionDescriptor.getReceiverType() != null) { - iterator.remove(); - } - } - addConstrtuctors(scope, name, functions); - - List nonlocals = Lists.newArrayList(); - List locals = Lists.newArrayList(); - splitLexicallyLocalDescriptors(functions, scope.getContainingDeclaration(), locals, nonlocals); - - addTask(result, receiverType, call, locals); - - addTask(result, receiverType, call, nonlocals); - } - return result; - } - - private void addTask(List result, JetType receiverType, Call call, Collection candidates) { - if (candidates.isEmpty()) return; - result.add(new ResolutionTask(candidates, receiverType, call)); - } - - private void addConstrtuctors(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().getFunctionDescriptors()); - } - } - - private FunctionDescriptor resolveCallToFunctionDescriptor( + private Descriptor 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 functionReference) { + @NotNull final List> prioritizedTasks, // high to low priority + @NotNull final JetReferenceExpression reference) { TemporaryBindingTrace traceForFirstNonemptyCandidateSet = null; TracingStrategy tracing = new TracingStrategy() { @Override - public void bindFunctionReference(@NotNull BindingTrace trace, @NotNull FunctionDescriptor functionDescriptor) { - trace.record(BindingContext.REFERENCE_TARGET, functionReference, functionDescriptor); + public void bindReference(@NotNull BindingTrace trace, @NotNull CallableDescriptor descriptor) { + trace.record(REFERENCE_TARGET, reference, descriptor); } @Override @@ -289,22 +203,22 @@ public class CallResolver { } @Override - public void reportUnresolvedFunctionReference(@NotNull BindingTrace trace) { - trace.getErrorHandler().unresolvedReference(functionReference); + public void reportUnresolvedReference(@NotNull BindingTrace trace) { + trace.getErrorHandler().unresolvedReference(reference); } @Override - public void reportErrorOnFunctionReference(BindingTrace trace, String message) { - trace.getErrorHandler().genericError(functionReference.getNode(), message); + public void reportErrorOnReference(BindingTrace trace, String message) { + trace.getErrorHandler().genericError(reference.getNode(), message); } }; - for (ResolutionTask task : prioritizedTasks) { + for (ResolutionTask task : prioritizedTasks) { TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(trace); - FunctionDescriptor functionDescriptor = performResolution(temporaryTrace, scope, expectedType, task, tracing); - if (functionDescriptor != null) { + Descriptor descriptor = performResolution(temporaryTrace, scope, expectedType, task, tracing); + if (descriptor != null) { temporaryTrace.commit(); - return functionDescriptor; + return descriptor; } if (traceForFirstNonemptyCandidateSet == null && !task.getCandidates().isEmpty()) { traceForFirstNonemptyCandidateSet = temporaryTrace; @@ -314,144 +228,184 @@ public class CallResolver { traceForFirstNonemptyCandidateSet.commit(); } else { - trace.getErrorHandler().unresolvedReference(functionReference); + trace.getErrorHandler().unresolvedReference(reference); } return null; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - private boolean mapValueArgumentsToParameters( - @NotNull ResolutionTask task, - @NotNull TracingStrategy tracing, - @NotNull FunctionDescriptor candidate, - @NotNull BindingTrace temporaryTrace, - @NotNull Map argumentsToParameters - ) { - Set usedParameters = Sets.newHashSet(); + @Nullable + private > Descriptor performResolution(@NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull JetType expectedType, @NotNull Task task, @NotNull TracingStrategy tracing) { + Map successfulCandidates = Maps.newLinkedHashMap(); + Set failedCandidates = Sets.newLinkedHashSet(); + Set dirtyCandidates = Sets.newLinkedHashSet(); + Map solutions = Maps.newHashMap(); + Map traces = Maps.newHashMap(); - List valueParameters = candidate.getValueParameters(); + for (Descriptor candidate : task.getCandidates()) { + TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(trace); + traces.put(candidate, temporaryTrace); + JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace); - Map parameterByName = Maps.newHashMap(); - for (ValueParameterDescriptor valueParameter : valueParameters) { - parameterByName.put(valueParameter.getName(), valueParameter); - } + tracing.bindReference(temporaryTrace, candidate); + + if (ErrorUtils.isError(candidate)) { + successfulCandidates.put(candidate, candidate); + continue; + } - List valueArguments = task.getValueArguments(); + Flag dirty = new Flag(false); - boolean error = false; - boolean someNamed = false; - boolean somePositioned = false; - for (int i = 0; i < valueArguments.size(); i++) { - ValueArgument valueArgument = valueArguments.get(i); - if (valueArgument.isNamed()) { - someNamed = true; - ASTNode nameNode = valueArgument.getArgumentName().getNode(); - if (somePositioned) { - temporaryTrace.getErrorHandler().genericError(nameNode, "Mixing named and positioned arguments in not allowed"); - error = true; - } - else { - ValueParameterDescriptor valueParameterDescriptor = parameterByName.get(valueArgument.getArgumentName().getReferenceExpression().getReferencedName()); - if (!usedParameters.add(valueParameterDescriptor)) { - temporaryTrace.getErrorHandler().genericError(nameNode, "An argument is already passed for this parameter"); - } - if (valueParameterDescriptor == null) { - temporaryTrace.getErrorHandler().genericError(nameNode, "Cannot find a parameter with this name"); - error = true; + Map argumentsToParameters = Maps.newHashMap(); + boolean error = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(task, tracing, candidate, temporaryTrace, argumentsToParameters); + + if (error) { + failedCandidates.add(candidate); + 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 { - temporaryTrace.record(REFERENCE_TARGET, valueArgument.getArgumentName().getReferenceExpression(), valueParameterDescriptor); - argumentsToParameters.put(valueArgument, valueParameterDescriptor); + failedCandidates.add(candidate); + } + } + else { + // Type argument inference + + ConstraintSystem constraintSystem = new ConstraintSystem(); + for (TypeParameterDescriptor typeParameterDescriptor : candidate.getTypeParameters()) { + constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO + } + + for (Map.Entry entry : argumentsToParameters.entrySet()) { + ValueArgument valueArgument = entry.getKey(); + ValueParameterDescriptor valueParameterDescriptor = entry.getValue(); + + 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); + } + } + + checkReceiverAbsence(task, tracing, candidate, temporaryTrace); + // Error is already reported if something is missing + JetType receiverType = task.getReceiverType(); + JetType candidateReceiverType = candidate.getReceiverType(); + if (receiverType != null && candidateReceiverType != null) { + constraintSystem.addSubtypingConstraint(receiverType, candidateReceiverType); + } + + if (expectedType != NO_EXPECTED_TYPE) { + constraintSystem.addSubtypingConstraint(candidate.getReturnType(), expectedType); + } + + ConstraintSystem.Solution solution = constraintSystem.solve(); + solutions.put(candidate, solution); + if (solution.isSuccessful()) { + Descriptor substitute = (Descriptor) candidate.substitute(solution.getSubstitutor()); + assert substitute != null; + successfulCandidates.put(candidate, substitute); + } + else { + tracing.reportOverallResolutionError(temporaryTrace, "Type inference failed"); + failedCandidates.add(candidate); } } } else { - somePositioned = true; - if (someNamed) { - temporaryTrace.getErrorHandler().genericError(valueArgument.asElement().getNode(), "Mixing named and positioned arguments in not allowed"); - error = true; - } - else { - int parameterCount = valueParameters.size(); - if (i < parameterCount) { - ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(i); - usedParameters.add(valueParameterDescriptor); - argumentsToParameters.put(valueArgument, valueParameterDescriptor); + // 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 } - else if (!valueParameters.isEmpty()) { - ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1); - if (valueParameterDescriptor.isVararg()) { - argumentsToParameters.put(valueArgument, valueParameterDescriptor); - usedParameters.add(valueParameterDescriptor); - } - else { - temporaryTrace.getErrorHandler().genericError(valueArgument.asElement().getNode(), "Too many arguments"); - error = true; + } + + if (candidate.getTypeParameters().size() == jetTypeArguments.size()) { + List typeArguments = new ArrayList(); + for (JetTypeProjection projection : jetTypeArguments) { + // TODO : check that there's no projection + JetTypeReference typeReference = projection.getTypeReference(); + if (typeReference != null) { + typeArguments.add(new TypeResolver(semanticServices, temporaryTrace, true).resolveType(scope, typeReference)); } } - else { - temporaryTrace.getErrorHandler().genericError(valueArgument.asElement().getNode(), "Too many arguments"); - error = true; - } - } - } - } - List functionLiteralArguments = task.getFunctionLiteralArguments(); - if (!functionLiteralArguments.isEmpty()) { - JetExpression possiblyLabeledFunctionLiteral = functionLiteralArguments.get(0); + checkGenericBoundsInAFunctionCall(jetTypeArguments, typeArguments, candidate); - if (valueParameters.isEmpty()) { - temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), "Too many arguments"); - error = true; - } else { - JetFunctionLiteralExpression functionLiteral; - if (possiblyLabeledFunctionLiteral instanceof JetLabelQualifiedExpression) { - JetLabelQualifiedExpression labeledFunctionLiteral = (JetLabelQualifiedExpression) possiblyLabeledFunctionLiteral; - functionLiteral = (JetFunctionLiteralExpression) labeledFunctionLiteral.getLabeledExpression(); - } - else { - functionLiteral = (JetFunctionLiteralExpression) possiblyLabeledFunctionLiteral; - } + Map substitutionContext = FunctionDescriptorUtil.createSubstitutionContext((FunctionDescriptor) candidate, typeArguments); + Descriptor substitutedFunctionDescriptor = (Descriptor) candidate.substitute(TypeSubstitutor.create(substitutionContext)); - ValueParameterDescriptor parameterDescriptor = valueParameters.get(valueParameters.size() - 1); - if (parameterDescriptor.isVararg()) { - temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), "Passing value as a vararg is only allowed inside a parenthesized argument list"); - error = true; - } - else { - if (!usedParameters.add(parameterDescriptor)) { - temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), "Too many arguments"); - error = true; + Function mapFunction = createMapFunction(substitutedFunctionDescriptor); + if (checkValueArgumentTypes(scope, temporaryServices, argumentsToParameters, dirty, mapFunction) + && checkReceiver(task, tracing, substitutedFunctionDescriptor, temporaryTrace)) { + successfulCandidates.put(candidate, substitutedFunctionDescriptor); } else { - argumentsToParameters.put(CallMaker.makeValueArgument(functionLiteral), parameterDescriptor); + failedCandidates.add(candidate); } } - } - - for (int i = 1; i < functionLiteralArguments.size(); i++) { - JetExpression argument = functionLiteralArguments.get(i); - temporaryTrace.getErrorHandler().genericError(argument.getNode(), "Only one function literal is allowed outside a parenthesized argument list"); - error = true; - } - } - - - for (ValueParameterDescriptor valueParameter : valueParameters) { - if (!usedParameters.contains(valueParameter)) { - if (!valueParameter.hasDefaultValue()) { - tracing.reportWrongValueArguments(temporaryTrace, "No value passed for parameter " + valueParameter.getName()); - error = true; + else { + failedCandidates.add(candidate); + tracing.reportWrongTypeArguments(temporaryTrace, "Number of type arguments does not match " + DescriptorRenderer.TEXT.render(candidate)); } } + + if (dirty.getValue()) { + dirtyCandidates.add(candidate); + } } - return error; + + Descriptor resultingDescriptor = computeResultAndReportErrors(trace, tracing, successfulCandidates, failedCandidates, dirtyCandidates, traces); + if (resultingDescriptor == null) { + for (ValueArgument valueArgument : task.getValueArguments()) { + JetExpression argumentExpression = valueArgument.getArgumentExpression(); + if (argumentExpression != null) { + typeInferrer.getServices(trace).getType(scope, argumentExpression, NO_EXPECTED_TYPE); + } + } + + for (JetExpression expression : task.getFunctionLiteralArguments()) { + typeInferrer.getServices(trace).getType(scope, expression, NO_EXPECTED_TYPE); + } + + for (JetTypeProjection typeProjection : task.getTypeArguments()) { + new TypeResolver(semanticServices, trace, true).resolveType(scope, typeProjection.getTypeReference()); + } + } + return resultingDescriptor; + } + + private Function createMapFunction(Descriptor 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()); + } + }; } @Nullable - private FunctionDescriptor performResolution(@NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull JetType expectedType, @NotNull ResolutionTask task, @NotNull TracingStrategy tracing) { + private FunctionDescriptor oldPerformResolution(@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(); @@ -463,8 +417,8 @@ public class CallResolver { traces.put(candidate, temporaryTrace); JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace); - tracing.bindFunctionReference(temporaryTrace, candidate); - + tracing.bindReference(temporaryTrace, candidate); + if (ErrorUtils.isError(candidate)) { successfulCandidates.put(candidate, candidate); continue; @@ -473,7 +427,7 @@ public class CallResolver { Flag dirty = new Flag(false); Map argumentsToParameters = Maps.newHashMap(); - boolean error = mapValueArgumentsToParameters(task, tracing, candidate, temporaryTrace, argumentsToParameters); + boolean error = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(task, tracing, candidate, temporaryTrace, argumentsToParameters); if (error) { failedCandidates.add(candidate); @@ -588,7 +542,7 @@ public class CallResolver { tracing.reportWrongTypeArguments(temporaryTrace, "Number of type arguments does not match " + DescriptorRenderer.TEXT.render(candidate)); } } - + if (dirty.getValue()) { dirtyCandidates.add(candidate); } @@ -614,66 +568,66 @@ public class CallResolver { return functionDescriptor; } - private boolean checkReceiver(ResolutionTask task, TracingStrategy tracing, FunctionDescriptor candidate, TemporaryBindingTrace temporaryTrace) { + private boolean checkReceiver(ResolutionTask task, TracingStrategy tracing, Descriptor candidate, TemporaryBindingTrace temporaryTrace) { if (!checkReceiverAbsence(task, tracing, candidate, temporaryTrace)) return false; JetType receiverType = task.getReceiverType(); JetType candidateReceiverType = candidate.getReceiverType(); if (receiverType != null && candidateReceiverType != null && !semanticServices.getTypeChecker().isSubtypeOf(receiverType, candidateReceiverType)) { - tracing.reportErrorOnFunctionReference(temporaryTrace, "This function requires a receiver of type " + candidateReceiverType); + tracing.reportErrorOnReference(temporaryTrace, "This function requires a receiver of type " + candidateReceiverType); return false; } return true; } - private boolean checkReceiverAbsence(ResolutionTask task, TracingStrategy tracing, FunctionDescriptor candidate, TemporaryBindingTrace temporaryTrace) { + private boolean checkReceiverAbsence(ResolutionTask task, TracingStrategy tracing, Descriptor candidate, TemporaryBindingTrace temporaryTrace) { JetType receiverType = task.getReceiverType(); JetType candidateReceiverType = candidate.getReceiverType(); if (receiverType != null) { if (candidateReceiverType == null) { - tracing.reportErrorOnFunctionReference(temporaryTrace, "This function does not admit a receiver"); + tracing.reportErrorOnReference(temporaryTrace, "This function does not admit a receiver"); return false; } } else if (candidateReceiverType != null) { - tracing.reportErrorOnFunctionReference(temporaryTrace, "Receiver is missing" + candidateReceiverType); + tracing.reportErrorOnReference(temporaryTrace, "Receiver is missing" + candidateReceiverType); return false; } return true; } @Nullable - private FunctionDescriptor computeResultAndReportErrors(BindingTrace trace, TracingStrategy tracing, Map successfulCandidates, Set failedCandidates, Set dirtyCandidates, Map traces) { + private Descriptor computeResultAndReportErrors(BindingTrace trace, TracingStrategy tracing, Map successfulCandidates, Set failedCandidates, Set dirtyCandidates, Map traces) { if (successfulCandidates.size() > 0) { if (successfulCandidates.size() == 1) { - Map.Entry entry = successfulCandidates.entrySet().iterator().next(); - FunctionDescriptor functionDescriptor = entry.getKey(); - FunctionDescriptor result = entry.getValue(); + Map.Entry entry = successfulCandidates.entrySet().iterator().next(); + Descriptor functionDescriptor = entry.getKey(); + Descriptor result = entry.getValue(); TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor); temporaryTrace.commit(); return result; } else { - Map cleanCandidates = Maps.newLinkedHashMap(successfulCandidates); + Map cleanCandidates = Maps.newLinkedHashMap(successfulCandidates); cleanCandidates.keySet().removeAll(dirtyCandidates); if (cleanCandidates.isEmpty()) { cleanCandidates = successfulCandidates; } - FunctionDescriptor maximallySpecific = findMaximallySpecific(cleanCandidates, traces, false); + Descriptor maximallySpecific = overloadingConflictResolver.findMaximallySpecific(cleanCandidates, traces, false); if (maximallySpecific != null) { return maximallySpecific; } - FunctionDescriptor maximallySpecificGenericsDiscriminated = findMaximallySpecific(cleanCandidates, traces, true); + Descriptor maximallySpecificGenericsDiscriminated = overloadingConflictResolver.findMaximallySpecific(cleanCandidates, traces, true); if (maximallySpecificGenericsDiscriminated != null) { return maximallySpecificGenericsDiscriminated; } if (dirtyCandidates.isEmpty()) { StringBuilder stringBuilder = new StringBuilder(); - for (FunctionDescriptor functionDescriptor : successfulCandidates.keySet()) { + for (Descriptor functionDescriptor : successfulCandidates.keySet()) { stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append(" "); } @@ -683,14 +637,14 @@ public class CallResolver { } else if (!failedCandidates.isEmpty()) { if (failedCandidates.size() == 1) { - FunctionDescriptor functionDescriptor = failedCandidates.iterator().next(); + Descriptor functionDescriptor = failedCandidates.iterator().next(); TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor); temporaryTrace.commit(); return failedCandidates.iterator().next(); } else { StringBuilder stringBuilder = new StringBuilder(); - for (FunctionDescriptor functionDescriptor : failedCandidates) { + for (Descriptor functionDescriptor : failedCandidates) { stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append(" "); } @@ -698,7 +652,7 @@ public class CallResolver { } } else { - tracing.reportUnresolvedFunctionReference(trace); + tracing.reportUnresolvedReference(trace); } @@ -730,104 +684,7 @@ public class CallResolver { return true; } - @Nullable - private FunctionDescriptor findMaximallySpecific(Map candidates, Map traces, boolean discriminateGenericFunctions) { - Map maximallySpecific = Maps.newHashMap(); - meLoop: - for (Map.Entry myEntry : candidates.entrySet()) { - FunctionDescriptor me = myEntry.getValue(); - TemporaryBindingTrace myTrace = traces.get(myEntry.getKey()); - for (FunctionDescriptor other : candidates.values()) { - if (other == me) continue; - if (!moreSpecific(me, other, discriminateGenericFunctions) || moreSpecific(other, me, discriminateGenericFunctions)) continue meLoop; - } - maximallySpecific.put(me, myTrace); - } - if (maximallySpecific.size() == 1) { - Map.Entry result = maximallySpecific.entrySet().iterator().next(); - result.getValue().commit(); - return result.getKey(); - } - return null; - } - - /** - * Let < mean "more specific" - * Subtype < supertype - * Double < Float - * Int < Long - * Int < Short < Byte - */ - private boolean moreSpecific(FunctionDescriptor f, FunctionDescriptor g, boolean discriminateGenericFunctions) { - if (overrides(f, g)) return true; - if (overrides(g, f)) return false; - - List fParams = f.getValueParameters(); - List gParams = g.getValueParameters(); - - int fSize = fParams.size(); - if (fSize != gParams.size()) return false; - for (int i = 0; i < fSize; i++) { - JetType fParamType = fParams.get(i).getOutType(); - JetType gParamType = gParams.get(i).getOutType(); - - if (!semanticServices.getTypeChecker().isSubtypeOf(fParamType, gParamType) - && !numericTypeMoreSpecific(fParamType, gParamType) - ) { - return false; - } - } - - if (discriminateGenericFunctions && isGenericFunction(f)) { - if (!isGenericFunction(g)) { - return false; - } - - // g is generic, too - - return moreSpecific(FunctionDescriptorUtil.substituteBounds(f), FunctionDescriptorUtil.substituteBounds(g), false); - } - - return true; - } - - private boolean isGenericFunction(FunctionDescriptor f) { - return !f.getOriginal().getTypeParameters().isEmpty(); - } - - private boolean numericTypeMoreSpecific(@NotNull JetType specific, @NotNull JetType general) { - JetStandardLibrary standardLibrary = semanticServices.getStandardLibrary(); - JetType _double = standardLibrary.getDoubleType(); - JetType _float = standardLibrary.getFloatType(); - JetType _long = standardLibrary.getLongType(); - JetType _int = standardLibrary.getIntType(); - JetType _byte = standardLibrary.getByteType(); - JetType _short = standardLibrary.getShortType(); - - if (eq(specific, _double) && eq(general, _float)) return true; - if (eq(specific, _int)) { - if (eq(general, _long)) return true; - if (eq(general, _byte)) return true; - if (eq(general, _short)) return true; - } - if (eq(specific, _short) && eq(general, _byte)) return true; - return false; - } - - private boolean eq(@NotNull JetType a, @NotNull JetType b) { - return semanticServices.getTypeChecker().isSubtypeOf(a, b) && semanticServices.getTypeChecker().isSubtypeOf(b, a); - } - - private boolean overrides(@NotNull FunctionDescriptor f, @NotNull FunctionDescriptor g) { - Set overriddenFunctions = f.getOriginal().getOverriddenFunctions(); - FunctionDescriptor originalG = g.getOriginal(); - for (FunctionDescriptor overriddenFunction : overriddenFunctions) { - if (originalG.equals(overriddenFunction.getOriginal())) return true; - } - return false; - } - - public void checkGenericBoundsInAFunctionCall(List jetTypeArguments, List typeArguments, FunctionDescriptor functionDescriptor) { + public void checkGenericBoundsInAFunctionCall(List jetTypeArguments, List typeArguments, CallableDescriptor functionDescriptor) { Map context = Maps.newHashMap(); List typeParameters = functionDescriptor.getOriginal().getTypeParameters(); @@ -858,7 +715,7 @@ public class CallResolver { Set extensionFunctionDescriptors = scope.getFunctionGroup(name).getFunctionDescriptors(); List nonlocal = Lists.newArrayList(); List local = Lists.newArrayList(); - splitLexicallyLocalDescriptors(extensionFunctionDescriptors, scope.getContainingDeclaration(), local, nonlocal); + TaskPrioritizer.splitLexicallyLocalDescriptors(extensionFunctionDescriptors, scope.getContainingDeclaration(), local, nonlocal); if (findExtensionFunctions(local, receiverType, parameterTypes, result)) { @@ -917,59 +774,170 @@ public class CallResolver { return found; } - private void splitLexicallyLocalDescriptors( - Collection allDescriptors, DeclarationDescriptor containerOfTheCurrentLocality, List local, List nonlocal) { - - for (T descriptor : allDescriptors) { - if (isLocal(containerOfTheCurrentLocality, descriptor)) { - local.add(descriptor); - } - else { - nonlocal.add(descriptor); - } - } - } - - /** - * The primary case for local extensions is the following: - * - * I had a locally declared extension function or a local variable of function type called foo - * And I called it on my x - * Now, someone added function foo() to the class of x - * My code should not change - * - * thus - * - * local extension prevail over members (and members prevail over all non-local extensions) - */ - private boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) { - DeclarationDescriptor parent = candidate.getContainingDeclaration(); - if (!(parent instanceof FunctionDescriptor)) { - return false; - } - FunctionDescriptor functionDescriptor = (FunctionDescriptor) parent; - DeclarationDescriptor current = containerOfTheCurrentLocality; - while (current != null) { - if (current == functionDescriptor) { - return true; - } - current = current.getContainingDeclaration(); - } - return false; - } - private boolean checkValueParameters(@NotNull FunctionDescriptor functionDescriptor, @NotNull List parameterTypes) { List valueParameters = functionDescriptor.getValueParameters(); if (valueParameters.size() != parameterTypes.size()) return false; for (int i = 0; i < valueParameters.size(); i++) { ValueParameterDescriptor valueParameter = valueParameters.get(i); JetType expectedType = parameterTypes.get(i); - if (!eq(expectedType, valueParameter.getOutType())) return false; + if (!semanticServices.getTypeChecker().equalTypes(expectedType, valueParameter.getOutType())) return false; } return true; } + private static TaskPrioritizer FUNCTION_TASK_PRIORITIZER = new TaskPrioritizer() { + + @NotNull + @Override + protected Collection getNonExtensionsByName(JetScope scope, String name) { + Set functions = Sets.newLinkedHashSet(scope.getFunctionGroup(name).getFunctionDescriptors()); + for (Iterator iterator = functions.iterator(); iterator.hasNext(); ) { + FunctionDescriptor functionDescriptor = iterator.next(); + if (functionDescriptor.getReceiverType() != null) { + iterator.remove(); + } + } + addConstrtuctors(scope, name, functions); + return functions; + } + + @NotNull + @Override + protected Collection getMembersByName(@NotNull JetType receiverType, String name) { + Set members = Sets.newHashSet(receiverType.getMemberScope().getFunctionGroup(name).getFunctionDescriptors()); + addConstrtuctors(receiverType.getMemberScope(), name, members); + return members; + } + + @NotNull + @Override + protected Collection getExtensionsByName(JetScope scope, String name) { + Set extensionFunctions = Sets.newHashSet(scope.getFunctionGroup(name).getFunctionDescriptors()); + for (Iterator iterator = extensionFunctions.iterator(); iterator.hasNext(); ) { + FunctionDescriptor descriptor = iterator.next(); + if (descriptor.getReceiverType() == null) { + iterator.remove(); + } + } + return extensionFunctions; + } + + @NotNull + @Override + protected ResolutionTask createTask(JetType receiverType, Call call, Collection candidates) { + return new ResolutionTask(candidates, receiverType, call); + } + + private void addConstrtuctors(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().getFunctionDescriptors()); + } + } + + }; + + 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.getReceiverType() == null) { + 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.getReceiverType() != null) { + return Collections.singleton(variable); + } + return Collections.emptyList(); + } + + @NotNull + @Override + protected ResolutionTask createTask(JetType receiverType, Call call, Collection candidates) { + return new ResolutionTask(candidates, receiverType, call); + } + }; + + + private static class FunctionTaskPrioritizer1 { + + private List> computePrioritizedTasks(JetScope scope, JetType receiverType, Call call, String name) { + List> result = Lists.newArrayList(); + if (receiverType != null) { + Collection extensionFunctions = Sets.newLinkedHashSet(scope.getFunctionGroup(name).getFunctionDescriptors()); + for (Iterator iterator = extensionFunctions.iterator(); iterator.hasNext(); ) { + FunctionDescriptor functionDescriptor = iterator.next(); + if (functionDescriptor.getReceiverType() == null) { + iterator.remove(); + } + } + List nonlocals = Lists.newArrayList(); + List locals = Lists.newArrayList(); + TaskPrioritizer.splitLexicallyLocalDescriptors(extensionFunctions, scope.getContainingDeclaration(), locals, nonlocals); + + Set members = Sets.newHashSet(receiverType.getMemberScope().getFunctionGroup(name).getFunctionDescriptors()); + addConstrtuctors(receiverType.getMemberScope(), name, members); + + addTask(result, receiverType, call, locals); + addTask(result, null, call, members); + addTask(result, receiverType, call, nonlocals); + } + else { + Collection functions = Sets.newLinkedHashSet(scope.getFunctionGroup(name).getFunctionDescriptors()); + for (Iterator iterator = functions.iterator(); iterator.hasNext(); ) { + FunctionDescriptor functionDescriptor = iterator.next(); + if (functionDescriptor.getReceiverType() != null) { + iterator.remove(); + } + } + addConstrtuctors(scope, name, functions); + + List nonlocals = Lists.newArrayList(); + List locals = Lists.newArrayList(); + TaskPrioritizer.splitLexicallyLocalDescriptors(functions, scope.getContainingDeclaration(), locals, nonlocals); + + addTask(result, receiverType, call, locals); + + addTask(result, receiverType, call, nonlocals); + } + return result; + } + + private void addTask(List> result, JetType receiverType, Call call, Collection candidates) { + if (candidates.isEmpty()) return; + result.add(new ResolutionTask(candidates, receiverType, call)); + } + + private void addConstrtuctors(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().getFunctionDescriptors()); + } + } + + } + private static class Flag { private boolean flag; diff --git a/idea/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java new file mode 100644 index 00000000000..f257099be7e --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java @@ -0,0 +1,122 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import com.google.common.collect.Maps; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.JetSemanticServices; +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.TemporaryBindingTrace; +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 + */ +/*package*/ class OverloadingConflictResolver { + + private final JetSemanticServices semanticServices; + + public OverloadingConflictResolver(@NotNull JetSemanticServices semanticServices) { + this.semanticServices = semanticServices; + } + + @Nullable + public Descriptor findMaximallySpecific(Map candidates, Map traces, boolean discriminateGenericDescriptors) { + Map maximallySpecific = Maps.newHashMap(); + meLoop: + for (Map.Entry myEntry : candidates.entrySet()) { + Descriptor me = myEntry.getValue(); + TemporaryBindingTrace myTrace = traces.get(myEntry.getKey()); + for (Descriptor other : candidates.values()) { + if (other == me) continue; + if (!moreSpecific(me, other, discriminateGenericDescriptors) || moreSpecific(other, me, discriminateGenericDescriptors)) continue meLoop; + } + maximallySpecific.put(me, myTrace); + } + if (maximallySpecific.size() == 1) { + Map.Entry result = maximallySpecific.entrySet().iterator().next(); + result.getValue().commit(); + return result.getKey(); + } + return null; + } + + /** + * Let < mean "more specific" + * Subtype < supertype + * Double < Float + * Int < Long + * Int < Short < Byte + */ + private boolean moreSpecific(Descriptor f, Descriptor g, boolean discriminateGenericDescriptors) { + if (overrides(f, g)) return true; + if (overrides(g, f)) return false; + + List fParams = f.getValueParameters(); + List gParams = g.getValueParameters(); + + int fSize = fParams.size(); + if (fSize != gParams.size()) return false; + for (int i = 0; i < fSize; i++) { + JetType fParamType = fParams.get(i).getOutType(); + JetType gParamType = gParams.get(i).getOutType(); + + if (!semanticServices.getTypeChecker().isSubtypeOf(fParamType, gParamType) + && !numericTypeMoreSpecific(fParamType, gParamType) + ) { + return false; + } + } + + if (discriminateGenericDescriptors && isGeneric(f)) { + if (!isGeneric(g)) { + return false; + } + + // g is generic, too + + return moreSpecific(DescriptorUtils.substituteBounds(f), DescriptorUtils.substituteBounds(g), false); + } + + return true; + } + + private boolean isGeneric(CallableDescriptor f) { + return !f.getOriginal().getTypeParameters().isEmpty(); + } + + private boolean numericTypeMoreSpecific(@NotNull JetType specific, @NotNull JetType general) { + JetStandardLibrary standardLibrary = semanticServices.getStandardLibrary(); + JetType _double = standardLibrary.getDoubleType(); + JetType _float = standardLibrary.getFloatType(); + JetType _long = standardLibrary.getLongType(); + JetType _int = standardLibrary.getIntType(); + JetType _byte = standardLibrary.getByteType(); + JetType _short = standardLibrary.getShortType(); + + if (semanticServices.getTypeChecker().equalTypes(specific, _double) && semanticServices.getTypeChecker().equalTypes(general, _float)) return true; + if (semanticServices.getTypeChecker().equalTypes(specific, _int)) { + if (semanticServices.getTypeChecker().equalTypes(general, _long)) return true; + if (semanticServices.getTypeChecker().equalTypes(general, _byte)) return true; + if (semanticServices.getTypeChecker().equalTypes(general, _short)) return true; + } + if (semanticServices.getTypeChecker().equalTypes(specific, _short) && semanticServices.getTypeChecker().equalTypes(general, _byte)) return true; + return false; + } + + private boolean overrides(@NotNull Descriptor f, @NotNull Descriptor g) { + Set overriddenDescriptors = f.getOriginal().getOverriddenDescriptors(); + CallableDescriptor originalG = g.getOriginal(); + for (CallableDescriptor overriddenFunction : overriddenDescriptors) { + if (originalG.equals(overriddenFunction.getOriginal())) return true; + } + return false; + } + +} diff --git a/idea/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java b/idea/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java new file mode 100644 index 00000000000..9ba8ed26da1 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java @@ -0,0 +1,71 @@ +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.types.JetType; + +import java.util.Collection; +import java.util.List; + +/** + * @author abreslav + */ +/*package*/ class ResolutionTask { + private final Collection candidates; + private final JetType receiverType; + private final List typeArguments; + private final List valueArguments; + private final List functionLiteralArguments; + + public ResolutionTask( + @NotNull Collection candidates, + @Nullable JetType receiverType, + @NotNull List typeArguments, + @NotNull List valueArguments, + @NotNull List functionLiteralArguments) { + this.candidates = candidates; + this.receiverType = receiverType; + this.typeArguments = typeArguments; + this.valueArguments = valueArguments; + this.functionLiteralArguments = functionLiteralArguments; + } + + public ResolutionTask( + @NotNull Collection candidates, + @Nullable JetType receiverType, + @NotNull Call call + ) { + this(candidates, receiverType, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments()); + } + + @NotNull + public Collection getCandidates() { + return candidates; + } + + @Nullable + public JetType getReceiverType() { + return receiverType; + } + + @NotNull + public List getTypeArguments() { + return typeArguments; + } + + @NotNull + public List getValueArguments() { + return valueArguments; + } + + @NotNull + public List getFunctionLiteralArguments() { + return functionLiteralArguments; + } + +} diff --git a/idea/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java b/idea/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java new file mode 100644 index 00000000000..c0fa67291bc --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java @@ -0,0 +1,108 @@ +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.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.CallableDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.psi.Call; +import org.jetbrains.jet.lang.resolve.JetScope; +import org.jetbrains.jet.lang.types.JetType; + +import java.util.Collection; +import java.util.List; + +/** +* @author abreslav +*/ +/*package*/ abstract class TaskPrioritizer { + + public static void splitLexicallyLocalDescriptors( + Collection allDescriptors, DeclarationDescriptor containerOfTheCurrentLocality, List local, List nonlocal) { + + for (T descriptor : allDescriptors) { + if (isLocal(containerOfTheCurrentLocality, descriptor)) { + local.add(descriptor); + } + else { + nonlocal.add(descriptor); + } + } + } + + /** + * The primary case for local extensions is the following: + * + * I had a locally declared extension function or a local variable of function type called foo + * And I called it on my x + * Now, someone added function foo() to the class of x + * My code should not change + * + * thus + * + * local extension prevail over members (and members prevail over all non-local extensions) + */ + public static boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) { + DeclarationDescriptor parent = candidate.getContainingDeclaration(); + if (!(parent instanceof FunctionDescriptor)) { + return false; + } + FunctionDescriptor functionDescriptor = (FunctionDescriptor) parent; + DeclarationDescriptor current = containerOfTheCurrentLocality; + while (current != null) { + if (current == functionDescriptor) { + return true; + } + current = current.getContainingDeclaration(); + } + return false; + } + + public List> computePrioritizedTasks(JetScope scope, JetType receiverType, Call call, String name) { + List> result = Lists.newArrayList(); + if (receiverType != null) { + Collection extensionFunctions = getExtensionsByName(scope, name); + + List nonlocals = Lists.newArrayList(); + List locals = Lists.newArrayList(); + splitLexicallyLocalDescriptors(extensionFunctions, scope.getContainingDeclaration(), locals, nonlocals); + + Collection members = getMembersByName(receiverType, name); + + addTask(result, receiverType, call, locals); + addTask(result, null, call, members); + addTask(result, receiverType, call, nonlocals); + } + else { + Collection functions = getNonExtensionsByName(scope, name); + + List nonlocals = Lists.newArrayList(); + List locals = Lists.newArrayList(); + splitLexicallyLocalDescriptors(functions, scope.getContainingDeclaration(), locals, nonlocals); + + addTask(result, receiverType, call, locals); + + addTask(result, receiverType, call, nonlocals); + } + return result; + } + + @NotNull + protected abstract Collection getNonExtensionsByName(JetScope scope, String name); + + @NotNull + protected abstract Collection getMembersByName(@NotNull JetType receiverType, String name); + + @NotNull + protected abstract Collection getExtensionsByName(JetScope scope, String name); + + private void addTask(@NotNull List> result, @Nullable JetType receiverType, @NotNull Call call, @NotNull Collection candidates) { + if (candidates.isEmpty()) return; + result.add(createTask(receiverType, call, candidates)); + } + + @NotNull + protected abstract ResolutionTask createTask(JetType receiverType, Call call, Collection candidates); + +} diff --git a/idea/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java b/idea/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java new file mode 100644 index 00000000000..331bd52b239 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java @@ -0,0 +1,22 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.CallableDescriptor; +import org.jetbrains.jet.lang.resolve.BindingTrace; + +/** +* @author abreslav +*/ +/*package*/ interface TracingStrategy { + void bindReference(@NotNull BindingTrace trace, @NotNull CallableDescriptor descriptor); + + void reportOverallResolutionError(@NotNull BindingTrace trace, @NotNull String message); + + void reportWrongTypeArguments(@NotNull BindingTrace trace, @NotNull String message); + + void reportWrongValueArguments(@NotNull BindingTrace trace, @NotNull String message); + + void reportUnresolvedReference(@NotNull BindingTrace trace); + + void reportErrorOnReference(BindingTrace trace, String message); +} diff --git a/idea/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java b/idea/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java new file mode 100644 index 00000000000..f784d6cd894 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java @@ -0,0 +1,154 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.intellij.lang.ASTNode; +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.JetExpression; +import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression; +import org.jetbrains.jet.lang.psi.JetLabelQualifiedExpression; +import org.jetbrains.jet.lang.psi.ValueArgument; +import org.jetbrains.jet.lang.resolve.BindingTrace; +import org.jetbrains.jet.lang.types.CallMaker; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; + +/** + * @author abreslav + */ +/*package*/ class ValueArgumentsToParametersMapper { + public static boolean mapValueArgumentsToParameters( + @NotNull ResolutionTask task, + @NotNull TracingStrategy tracing, + @NotNull Descriptor candidate, + @NotNull BindingTrace temporaryTrace, + @NotNull Map argumentsToParameters + ) { + Set usedParameters = Sets.newHashSet(); + + List valueParameters = candidate.getValueParameters(); + + Map parameterByName = Maps.newHashMap(); + for (ValueParameterDescriptor valueParameter : valueParameters) { + parameterByName.put(valueParameter.getName(), valueParameter); + } + + List valueArguments = task.getValueArguments(); + + boolean error = false; + boolean someNamed = false; + boolean somePositioned = false; + for (int i = 0; i < valueArguments.size(); i++) { + ValueArgument valueArgument = valueArguments.get(i); + if (valueArgument.isNamed()) { + someNamed = true; + ASTNode nameNode = valueArgument.getArgumentName().getNode(); + if (somePositioned) { + temporaryTrace.getErrorHandler().genericError(nameNode, "Mixing named and positioned arguments in not allowed"); + error = true; + } + else { + ValueParameterDescriptor valueParameterDescriptor = parameterByName.get(valueArgument.getArgumentName().getReferenceExpression().getReferencedName()); + if (!usedParameters.add(valueParameterDescriptor)) { + temporaryTrace.getErrorHandler().genericError(nameNode, "An argument is already passed for this parameter"); + } + if (valueParameterDescriptor == null) { + temporaryTrace.getErrorHandler().genericError(nameNode, "Cannot find a parameter with this name"); + error = true; + } + else { + temporaryTrace.record(REFERENCE_TARGET, valueArgument.getArgumentName().getReferenceExpression(), valueParameterDescriptor); + argumentsToParameters.put(valueArgument, valueParameterDescriptor); + } + } + } + else { + somePositioned = true; + if (someNamed) { + temporaryTrace.getErrorHandler().genericError(valueArgument.asElement().getNode(), "Mixing named and positioned arguments in not allowed"); + error = true; + } + else { + int parameterCount = valueParameters.size(); + if (i < parameterCount) { + ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(i); + usedParameters.add(valueParameterDescriptor); + argumentsToParameters.put(valueArgument, valueParameterDescriptor); + } + else if (!valueParameters.isEmpty()) { + ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1); + if (valueParameterDescriptor.isVararg()) { + argumentsToParameters.put(valueArgument, valueParameterDescriptor); + usedParameters.add(valueParameterDescriptor); + } + else { + temporaryTrace.getErrorHandler().genericError(valueArgument.asElement().getNode(), "Too many arguments"); + error = true; + } + } + else { + temporaryTrace.getErrorHandler().genericError(valueArgument.asElement().getNode(), "Too many arguments"); + error = true; + } + } + } + } + + List functionLiteralArguments = task.getFunctionLiteralArguments(); + if (!functionLiteralArguments.isEmpty()) { + JetExpression possiblyLabeledFunctionLiteral = functionLiteralArguments.get(0); + + if (valueParameters.isEmpty()) { + temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), "Too many arguments"); + error = true; + } else { + JetFunctionLiteralExpression functionLiteral; + if (possiblyLabeledFunctionLiteral instanceof JetLabelQualifiedExpression) { + JetLabelQualifiedExpression labeledFunctionLiteral = (JetLabelQualifiedExpression) possiblyLabeledFunctionLiteral; + functionLiteral = (JetFunctionLiteralExpression) labeledFunctionLiteral.getLabeledExpression(); + } + else { + functionLiteral = (JetFunctionLiteralExpression) possiblyLabeledFunctionLiteral; + } + + ValueParameterDescriptor parameterDescriptor = valueParameters.get(valueParameters.size() - 1); + if (parameterDescriptor.isVararg()) { + temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), "Passing value as a vararg is only allowed inside a parenthesized argument list"); + error = true; + } + else { + if (!usedParameters.add(parameterDescriptor)) { + temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), "Too many arguments"); + error = true; + } + else { + argumentsToParameters.put(CallMaker.makeValueArgument(functionLiteral), parameterDescriptor); + } + } + } + + for (int i = 1; i < functionLiteralArguments.size(); i++) { + JetExpression argument = functionLiteralArguments.get(i); + temporaryTrace.getErrorHandler().genericError(argument.getNode(), "Only one function literal is allowed outside a parenthesized argument list"); + error = true; + } + } + + + for (ValueParameterDescriptor valueParameter : valueParameters) { + if (!usedParameters.contains(valueParameter)) { + if (!valueParameter.hasDefaultValue()) { + tracing.reportWrongValueArguments(temporaryTrace, "No value passed for parameter " + valueParameter.getName()); + error = true; + } + } + } + return error; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/CallMaker.java b/idea/src/org/jetbrains/jet/lang/types/CallMaker.java index d01ad213406..16fa5949118 100644 --- a/idea/src/org/jetbrains/jet/lang/types/CallMaker.java +++ b/idea/src/org/jetbrains/jet/lang/types/CallMaker.java @@ -17,8 +17,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); } @@ -58,14 +58,14 @@ public class CallMaker { public PsiElement asElement() { return reportErrorsOn; } - } + } private static abstract class CallStub implements Call { + @Override public JetValueArgumentList getValueArgumentList() { return null; } - @NotNull @Override public List getFunctionLiteralArguments() { @@ -82,8 +82,8 @@ public class CallMaker { public JetTypeArgumentList getTypeArgumentList() { return null; } - } + } public static Call makeCallWithArguments(final JetExpression calleeExpression, final List valueArguments) { return new CallStub() { @Override @@ -128,4 +128,8 @@ public class CallMaker { public static ValueArgument makeValueArgument(@Nullable JetExpression expression, @NotNull PsiElement reportErrorsOn) { return new ExpressionValueArgument(expression, reportErrorsOn); } + + public static Call makePropertyCall(@NotNull JetSimpleNameExpression nameExpression) { + return makeCall(nameExpression, Collections.emptyList()); + } } diff --git a/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java b/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java index 0c159b76bb6..d4d780c7231 100644 --- a/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java +++ b/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java @@ -181,7 +181,7 @@ public class ErrorUtils { isError(type.getConstructor())); } - public static boolean isError(@NotNull FunctionDescriptor candidate) { + public static boolean isError(@NotNull DeclarationDescriptor candidate) { return candidate.getContainingDeclaration() == getErrorClass(); } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java index ba36527a44e..4da7a4baddf 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java @@ -334,6 +334,10 @@ public class JetTypeChecker { return new TypeCheckingProcedure().run(subtype, supertype); } + public boolean equalTypes(@NotNull JetType a, @NotNull JetType b) { + return isSubtypeOf(a, b) && isSubtypeOf(b, a); + } + private static class OldProcedure { public static boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) { if (ErrorUtils.isErrorType(subtype) || ErrorUtils.isErrorType(supertype)) { @@ -593,7 +597,5 @@ public class JetTypeChecker { protected Boolean result() { return result; } - - } } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 8bec7d0d118..b72986fa133 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -18,6 +18,7 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.*; +import org.jetbrains.jet.lang.resolve.calls.CallResolver; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver; import org.jetbrains.jet.lang.resolve.constants.ErrorValue; @@ -662,7 +663,7 @@ public class JetTypeInferrer { try { result = expression.visit(this, context); // Some recursive definitions (object expressions) must put their types in the cache manually: - if ((boolean) context.trace.get(BindingContext.PROCESSED, expression)) { + if (context.trace.get(BindingContext.PROCESSED, expression)) { return context.trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression); } @@ -730,41 +731,70 @@ public class JetTypeInferrer { } } else { - assert JetTokens.IDENTIFIER == expression.getReferencedNameElementType(); - if (referencedName != null) { - VariableDescriptor variable = context.scope.getVariable(referencedName); - if (variable != null) { - context.trace.record(REFERENCE_TARGET, expression, variable); - JetType result = variable.getOutType(); - if (result == null) { - context.trace.getErrorHandler().genericError(expression.getNode(), "This variable is not readable in this context"); - } - return context.services.checkEnrichedType(result, expression, context); - } - else { - ClassifierDescriptor classifier = context.scope.getClassifier(referencedName); - 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.record(REFERENCE_TARGET, expression, classifier); - return context.services.checkEnrichedType(result, expression, context); - } - else { - JetType[] result = new JetType[1]; - if (furtherNameLookup(expression, referencedName, result, context)) { - return context.services.checkEnrichedType(result[0], expression, context); - } - - } - } - context.trace.getErrorHandler().unresolvedReference(expression); + return getSelectorReturnType(null, expression, context); // TODO : Extensions to this +// assert JetTokens.IDENTIFIER == expression.getReferencedNameElementType(); +// if (referencedName != null) { +// VariableDescriptor variable = context.scope.getVariable(referencedName); +// if (variable != null) { +// context.trace.record(REFERENCE_TARGET, expression, variable); +// JetType result = variable.getOutType(); +// if (result == null) { +// context.trace.getErrorHandler().genericError(expression.getNode(), "This variable is not readable in this context"); +// } +// return context.services.checkEnrichedType(result, expression, context); +// } +// else { +// return lookupNamespaceOrClassObject(expression, referencedName, context); +// ClassifierDescriptor classifier = context.scope.getClassifier(referencedName); +// 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.record(REFERENCE_TARGET, expression, classifier); +// return context.services.checkEnrichedType(result, expression, context); +// } +// else { +// JetType[] result = new JetType[1]; +// if (furtherNameLookup(expression, referencedName, result, context)) { +// return context.services.checkEnrichedType(result[0], expression, context); +// } +// +// } +// } +// context.trace.getErrorHandler().unresolvedReference(expression); +// } + } + return null; + } + + private JetType lookupNamespaceOrClassObject(JetSimpleNameExpression expression, String referencedName, TypeInferenceContext context) { + ClassifierDescriptor classifier = context.scope.getClassifier(referencedName); + 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.record(REFERENCE_TARGET, expression, classifier); + if (result == null) { + return ErrorUtils.createErrorType("No class object in " + expression.getReferencedName()); + } + return context.services.checkEnrichedType(result, expression, context); + } + else { + JetType[] result = new JetType[1]; + if (furtherNameLookup(expression, referencedName, result, context)) { + return context.services.checkEnrichedType(result[0], expression, context); + } + } return null; } @@ -1945,11 +1975,25 @@ public class JetTypeInferrer { @Nullable private JetType getSelectorReturnType(@Nullable JetType receiverType, @NotNull JetExpression selectorExpression, @NotNull TypeInferenceContext context) { if (selectorExpression instanceof JetCallExpression) { - return context.services.callResolver.resolveCall(context.scope, receiverType, (JetCallExpression) selectorExpression, context.expectedType); + return context.services.callResolver.resolveCall(context.trace, context.scope, receiverType, (JetCallExpression) selectorExpression, context.expectedType); } else if (selectorExpression instanceof JetSimpleNameExpression) { - JetScope scope = receiverType != null ? receiverType.getMemberScope() : context.scope; - return getType(selectorExpression, context.replaceScope(scope)); + JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) selectorExpression; + + TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace); + VariableDescriptor variableDescriptor = context.services.callResolver.resolveSimpleProperty(temporaryTrace, context.scope, receiverType, nameExpression, context.expectedType); + if (variableDescriptor != null) { + temporaryTrace.commit(); + return context.services.checkEnrichedType(variableDescriptor.getOutType(), nameExpression, context); + } + TypeInferenceContext newContext = receiverType == null ? context : context.replaceScope(receiverType.getMemberScope()); + JetType jetType = lookupNamespaceOrClassObject(nameExpression, nameExpression.getReferencedName(), newContext); + if (jetType == null) { + context.trace.getErrorHandler().unresolvedReference(nameExpression); + } + return context.services.checkEnrichedType(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; @@ -1968,7 +2012,7 @@ public class JetTypeInferrer { @Override public JetType visitCallExpression(JetCallExpression expression, TypeInferenceContext context) { - JetType expressionType = context.services.callResolver.resolveCall(context.scope, null, expression, context.expectedType); + JetType expressionType = context.services.callResolver.resolveCall(context.trace, context.scope, null, expression, context.expectedType); return context.services.checkType(expressionType, expression, context); } @@ -2005,6 +2049,7 @@ public class JetTypeInferrer { if (receiverType == null) return null; FunctionDescriptor functionDescriptor = context.services.callResolver.resolveCallWithGivenName( + context.trace, context.scope, CallMaker.makeCall(expression), expression.getOperationSign(), @@ -2159,6 +2204,7 @@ public class JetTypeInferrer { String name = "contains"; JetType receiverType = context.services.safeGetType(context.scope, right, NO_EXPECTED_TYPE); FunctionDescriptor functionDescriptor = context.services.callResolver.resolveCallWithGivenName( + context.trace, context.scope, CallMaker.makeCall(operationSign, Collections.singletonList(left)), operationSign, @@ -2226,6 +2272,7 @@ public class JetTypeInferrer { if (receiverType != null) { FunctionDescriptor functionDescriptor = context.services.callResolver.resolveCallWithGivenName( + context.trace, context.scope, CallMaker.makeCall(expression, expression.getIndexExpressions()), expression, @@ -2243,6 +2290,7 @@ public class JetTypeInferrer { protected JetType getTypeForBinaryCall(JetScope scope, String name, TypeInferenceContext context, JetBinaryExpression binaryExpression) { JetType leftType = getType(binaryExpression.getLeft(), context.replaceScope(scope)); FunctionDescriptor functionDescriptor = context.services.callResolver.resolveCallWithGivenName( + context.trace, scope, CallMaker.makeCall(binaryExpression), binaryExpression.getOperationReference(), @@ -2479,10 +2527,11 @@ public class JetTypeInferrer { // arrayAccessExpression, // "set", arrayAccessExpression.getArrayExpression(), NO_EXPECTED_TYPE); FunctionDescriptor functionDescriptor = context.services.callResolver.resolveCallWithGivenName( - scope, - call, - arrayAccessExpression, - "set", receiverType, NO_EXPECTED_TYPE); + context.trace, + scope, + call, + arrayAccessExpression, + "set", receiverType, NO_EXPECTED_TYPE); if (functionDescriptor == null) return null; context.trace.record(REFERENCE_TARGET, operationSign, functionDescriptor); return context.services.checkType(functionDescriptor.getReturnType(), arrayAccessExpression, context); diff --git a/idea/src/org/jetbrains/jet/plugin/annotations/JetLineMarkerProvider.java b/idea/src/org/jetbrains/jet/plugin/annotations/JetLineMarkerProvider.java index aafe04c8cdb..6a5b14585c1 100644 --- a/idea/src/org/jetbrains/jet/plugin/annotations/JetLineMarkerProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/annotations/JetLineMarkerProvider.java @@ -64,7 +64,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider { final FunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, jetFunction); if (functionDescriptor == null) return null; - final Set overriddenFunctions = functionDescriptor.getOverriddenFunctions(); + final Set overriddenFunctions = functionDescriptor.getOverriddenDescriptors(); Icon icon = isMember(functionDescriptor) ? (overriddenFunctions.isEmpty() ? PlatformIcons.METHOD_ICON : OVERRIDING_FUNCTION) : PlatformIcons.FUNCTION_ICON; return new LineMarkerInfo( jetFunction, jetFunction.getTextOffset(), icon, Pass.UPDATE_ALL, diff --git a/idea/src/org/jetbrains/jet/resolve/DescriptorRenderer.java b/idea/src/org/jetbrains/jet/resolve/DescriptorRenderer.java index 7481e1aa8d2..8f2028f98e7 100644 --- a/idea/src/org/jetbrains/jet/resolve/DescriptorRenderer.java +++ b/idea/src/org/jetbrains/jet/resolve/DescriptorRenderer.java @@ -171,7 +171,7 @@ public class DescriptorRenderer { @Override public Void visitPropertyDescriptor(PropertyDescriptor descriptor, StringBuilder builder) { String typeString = renderPropertyPrefixAndComputeTypeString( - builder, descriptor.getTypeParemeters(), + builder, descriptor.getTypeParameters(), descriptor.getReceiverType(), descriptor.getOutType(), descriptor.getInType());