diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java index a6c3f0b9872..3dd21e79fea 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java @@ -132,7 +132,7 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements TypeSubstitutor substitutor = DescriptorSubstitutor.substituteTypeParameters(getTypeParameters(), originalSubstitutor, substitutedDescriptor, substitutedTypeParameters); JetType substitutedReceiverType = null; - if (receiver != NO_RECEIVER) { + if (receiver.exists()) { substitutedReceiverType = substitutor.substitute(getReceiver().getType(), Variance.IN_VARIANCE); if (substitutedReceiverType == null) { return null; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/AmbiguousDescriptorDiagnosticFactory.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/AmbiguousDescriptorDiagnosticFactory.java index f3cc1e2a67d..b9d4050f915 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/AmbiguousDescriptorDiagnosticFactory.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/AmbiguousDescriptorDiagnosticFactory.java @@ -1,7 +1,8 @@ package org.jetbrains.jet.lang.diagnostics; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.CallableDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.resolve.DescriptorRenderer; import java.util.Collection; @@ -9,7 +10,7 @@ import java.util.Collection; /** * @author abreslav */ -public class AmbiguousDescriptorDiagnosticFactory extends ParameterizedDiagnosticFactory1> { +public class AmbiguousDescriptorDiagnosticFactory extends ParameterizedDiagnosticFactory1>> { public static AmbiguousDescriptorDiagnosticFactory create(String messageTemplate) { return new AmbiguousDescriptorDiagnosticFactory(messageTemplate); } @@ -19,10 +20,10 @@ public class AmbiguousDescriptorDiagnosticFactory extends ParameterizedDiagnosti } @Override - protected String makeMessageFor(@NotNull Collection argument) { + protected String makeMessageFor(@NotNull Collection> argument) { StringBuilder stringBuilder = new StringBuilder("\n"); - for (CallableDescriptor descriptor : argument) { - stringBuilder.append(DescriptorRenderer.TEXT.render(descriptor)).append("\n"); + for (ResolvedCall call : argument) { + stringBuilder.append(DescriptorRenderer.TEXT.render(call.getResultingDescriptor())).append("\n"); } return stringBuilder.toString(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 58f6616fc0e..ff09318972b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -7,6 +7,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lexer.JetKeywordToken; import org.jetbrains.jet.resolve.DescriptorRenderer; @@ -352,8 +353,8 @@ public interface Errors { ParameterizedDiagnosticFactory3 RESULT_TYPE_MISMATCH = ParameterizedDiagnosticFactory3.create(ERROR, "{0} must return {1} but returns {2}"); ParameterizedDiagnosticFactory3 UNSAFE_INFIX_CALL = ParameterizedDiagnosticFactory3.create(ERROR, "Infix call corresponds to a dot-qualified call ''{0}.{1}({2})' which is not allowed on a nullable receiver ''{0}''. Use '?.'-qualified call instead"); - ParameterizedDiagnosticFactory1> OVERLOAD_RESOLUTION_AMBIGUITY = new AmbiguousDescriptorDiagnosticFactory("Overload resolution ambiguity: {0}"); - ParameterizedDiagnosticFactory1> NONE_APPLICABLE = new AmbiguousDescriptorDiagnosticFactory("None of the following functions can be called with the arguments supplied: {0}"); + AmbiguousDescriptorDiagnosticFactory OVERLOAD_RESOLUTION_AMBIGUITY = new AmbiguousDescriptorDiagnosticFactory("Overload resolution ambiguity: {0}"); + AmbiguousDescriptorDiagnosticFactory NONE_APPLICABLE = new AmbiguousDescriptorDiagnosticFactory("None of the following functions can be called with the arguments supplied: {0}"); ParameterizedDiagnosticFactory1 NO_VALUE_FOR_PARAMETER = ParameterizedDiagnosticFactory1.create(ERROR, "No value passed for parameter {0}", DescriptorRenderer.TEXT); ParameterizedDiagnosticFactory1 MISSING_RECEIVER = ParameterizedDiagnosticFactory1.create(ERROR, "A receiver of type {0} is required"); SimpleDiagnosticFactory NO_RECEIVER_ADMITTED = SimpleDiagnosticFactory.create(ERROR, "No receiver can be passed to this function or property"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java index 813118617a6..f00643ae6cb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java @@ -9,9 +9,11 @@ import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.psi.JetAnnotationEntry; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetModifierList; +import org.jetbrains.jet.lang.resolve.calls.CallResolver; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.types.DataFlowInfo; import org.jetbrains.jet.lang.types.ErrorUtils; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetTypeInferrer; @@ -27,11 +29,15 @@ import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE; public class AnnotationResolver { private final BindingTrace trace; - private final JetTypeInferrer typeInferrer; +// private final JetTypeInferrer typeInferrer; + private final CallResolver callResolver; +// private final JetTypeInferrer.Services services; public AnnotationResolver(JetSemanticServices semanticServices, BindingTrace trace) { - this.typeInferrer = new JetTypeInferrer(JetFlowInformationProvider.THROW_EXCEPTION, semanticServices); this.trace = trace; +// this.typeInferrer = new JetTypeInferrer(JetFlowInformationProvider.THROW_EXCEPTION, semanticServices); +// this.services = typeInferrer.getServices(this.trace); + this.callResolver = new CallResolver(semanticServices, new JetTypeInferrer(JetFlowInformationProvider.THROW_EXCEPTION, semanticServices), DataFlowInfo.getEmpty()); } @NotNull @@ -47,7 +53,7 @@ public class AnnotationResolver { } public void resolveAnnotationStub(@NotNull JetScope scope, @NotNull JetAnnotationEntry entryElement, @NotNull AnnotationDescriptor descriptor) { - JetType jetType = typeInferrer.getCallResolver().resolveCall(trace, scope, ReceiverDescriptor.NO_RECEIVER, entryElement, NO_EXPECTED_TYPE); + JetType jetType = callResolver.resolveCall(trace, scope, ReceiverDescriptor.NO_RECEIVER, entryElement, NO_EXPECTED_TYPE); descriptor.setAnnotationType(jetType == null ? ErrorUtils.createErrorType("Unresolved annotation type") : jetType); } @@ -112,4 +118,4 @@ public class AnnotationResolver { } return createAnnotationStubs(modifierList.getAnnotationEntries()); } -} \ No newline at end of file +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index c4b719d139a..d436f9bcdb2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -6,6 +6,7 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; @@ -28,7 +29,7 @@ public interface BindingContext { WritableSlice EXPRESSION_TYPE = new BasicWritableSlice("EXPRESSION_TYPE", RewritePolicy.DO_NOTHING); WritableSlice REFERENCE_TARGET = new BasicWritableSlice("REFERENCE_TARGET", RewritePolicy.DO_NOTHING); - WritableSlice> AMBIGUOUS_REFERENCE_TARGET = new BasicWritableSlice>("AMBIGUOUS_REFERENCE_TARGET", RewritePolicy.DO_NOTHING); + WritableSlice>> AMBIGUOUS_REFERENCE_TARGET = new BasicWritableSlice>>("AMBIGUOUS_REFERENCE_TARGET", RewritePolicy.DO_NOTHING); WritableSlice LOOP_RANGE_ITERATOR = Slices.createSimpleSlice("LOOP_RANGE_ITERATOR"); WritableSlice LOOP_RANGE_HAS_NEXT = Slices.createSimpleSlice("LOOP_RANGE_HAS_NEXT"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java index c8255af2f9d..4ee7c5c2fa7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -334,7 +334,7 @@ public class BodyResolver { public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) { JetTypeReference typeReference = call.getTypeReference(); if (typeReference != null) { - typeInferrerForInitializers.getCallResolver().resolveCall(context.getTrace(), functionInnerScope, null, call, NO_EXPECTED_TYPE); + typeInferrerForInitializers.getCallResolver().resolveCall(context.getTrace(), functionInnerScope, ReceiverDescriptor.NO_RECEIVER, call, NO_EXPECTED_TYPE); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java index 314f847b5ef..bc91949cc9b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java @@ -4,6 +4,7 @@ import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.types.*; @@ -37,24 +38,31 @@ public class OverridingUtil { } public static Set filterOverrides(Set candidateSet) { + return filterOverrides(candidateSet, Function.ID); + } + + public static Set filterOverrides(Set candidateSet, Function transform) { Set candidates = Sets.newLinkedHashSet(); outerLoop: - for (D me : candidateSet) { - for (D other : candidateSet) { + for (D meD : candidateSet) { + CallableDescriptor me = transform.fun(meD); + for (D otherD : candidateSet) { + CallableDescriptor other = transform.fun(otherD); if (me == other) continue; if (overrides(other, me)) { continue outerLoop; } } - for (D other : candidates) { + for (D otherD : candidates) { + CallableDescriptor other = transform.fun(otherD); if (me.getOriginal() == other.getOriginal() - && isOverridableBy(other, me).isSuccess() - && isOverridableBy(me, other).isSuccess()) { + && isOverridableBy(other, me).isSuccess() + && isOverridableBy(me, other).isSuccess()) { continue outerLoop; } } // System.out.println(me); - candidates.add(me); + candidates.add(meD); } // Set candidates = Sets.newLinkedHashSet(candidateSet); // for (D descriptor : candidateSet) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastUtils.java new file mode 100644 index 00000000000..cc8192251ce --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastUtils.java @@ -0,0 +1,116 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import com.google.common.collect.Lists; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.JetBinaryExpressionWithTypeRHS; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; +import org.jetbrains.jet.lang.psi.JetThisExpression; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.scopes.receivers.*; +import org.jetbrains.jet.lang.types.DataFlowInfo; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lexer.JetTokens; + +import java.util.Collections; +import java.util.List; + +import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; + +/** + * @author abreslav + */ +public class AutoCastUtils { + + private AutoCastUtils() {} + + public static List getAutocastVariants(@NotNull final BindingContext bindingContext, @NotNull final DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiverToCast) { + return receiverToCast.accept(new ReceiverDescriptorVisitor, Object>() { + @Override + public List visitNoReceiver(ReceiverDescriptor noReceiver, Object data) { + return Collections.emptyList(); + } + + @Override + public List visitTransientReceiver(TransientReceiver receiver, Object data) { + return Collections.emptyList(); + } + + @Override + public List visitExtensionReceiver(ExtensionReceiver receiver, Object data) { + return castThis(dataFlowInfo, receiver); + } + + @Override + public List visitClassReceiver(ClassReceiver receiver, Object data) { + return castThis(dataFlowInfo, receiver); + } + + @Override + public List visitExpressionReceiver(ExpressionReceiver receiver, Object data) { + JetExpression expression = receiver.getExpression(); + VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(bindingContext, expression); + if (variableDescriptor != null && isAutocastable(variableDescriptor)) { + List result = Lists.newArrayList(); + for (JetType possibleType : dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)) { + result.add(new AutocastReceiver(receiver, possibleType)); + } + return result; + } + else if (expression instanceof JetThisExpression) { + return castThis(dataFlowInfo, receiver); + } + return Collections.emptyList(); + } + }, null); + } + + private static List castThis(@NotNull DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiver) { + assert receiver.exists(); + List result = Lists.newArrayList(); + for (JetType possibleType : dataFlowInfo.getPossibleTypesForReceiver(receiver)) { + result.add(new AutocastReceiver(receiver, possibleType)); + } + return result; + } + + @Nullable + public static VariableDescriptor getVariableDescriptorFromSimpleName(@NotNull BindingContext bindingContext, @NotNull JetExpression receiverExpression) { + if (receiverExpression instanceof JetBinaryExpressionWithTypeRHS) { + JetBinaryExpressionWithTypeRHS expression = (JetBinaryExpressionWithTypeRHS) receiverExpression; + if (expression.getOperationSign().getReferencedNameElementType() == JetTokens.COLON) { + return getVariableDescriptorFromSimpleName(bindingContext, expression.getLeft()); + } + } + VariableDescriptor variableDescriptor = null; + if (receiverExpression instanceof JetSimpleNameExpression) { + JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) receiverExpression; + DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, nameExpression); + if (declarationDescriptor instanceof VariableDescriptor) { + variableDescriptor = (VariableDescriptor) declarationDescriptor; + } + } + return variableDescriptor; + } + + public static boolean isAutocastable(@NotNull VariableDescriptor variableDescriptor) { + if (variableDescriptor.isVar()) return false; + if (variableDescriptor instanceof PropertyDescriptor) { + PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor; + DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); + if (containingDeclaration instanceof ClassDescriptor) { + ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; + if (classDescriptor.getModality().isOverridable() && propertyDescriptor.getModality().isOverridable()) return false; + } + else { + assert !propertyDescriptor.getModality().isOverridable() : "Property outside a class must not be overridable"; + } + PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); + if (getter == null || !getter.isDefault()) return false; + } + return true; + } + +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutocastReceiver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutocastReceiver.java new file mode 100644 index 00000000000..97cb8439f6b --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutocastReceiver.java @@ -0,0 +1,29 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.resolve.scopes.receivers.AbstractReceiverDescriptor; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptorVisitor; +import org.jetbrains.jet.lang.types.JetType; + +/** + * @author abreslav + */ +public class AutocastReceiver extends AbstractReceiverDescriptor { + private final ReceiverDescriptor original; + + public AutocastReceiver(@NotNull ReceiverDescriptor original, @NotNull JetType castTo) { + super(castTo); + this.original = original; + } + + @NotNull + public ReceiverDescriptor getOriginal() { + return original; + } + + @Override + public R accept(@NotNull ReceiverDescriptorVisitor visitor, D data) { + throw new UnsupportedOperationException(); + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index 6089c27edd1..d74efee7ff5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -14,6 +14,7 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.inference.ConstraintSystem; @@ -21,9 +22,9 @@ import org.jetbrains.jet.lang.types.inference.ConstraintSystem; import java.util.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*; -import static org.jetbrains.jet.lang.resolve.BindingContext.AMBIGUOUS_REFERENCE_TARGET; -import static org.jetbrains.jet.lang.resolve.BindingContext.RECEIVER; -import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; +import static org.jetbrains.jet.lang.resolve.BindingContext.*; +import static org.jetbrains.jet.lang.resolve.calls.ResolvedCall.MAP_TO_CANDIDATE; +import static org.jetbrains.jet.lang.resolve.calls.ResolvedCall.MAP_TO_RESULT; import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER; import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE; @@ -35,11 +36,13 @@ public class CallResolver { private final JetTypeInferrer typeInferrer; private final JetSemanticServices semanticServices; private final OverloadingConflictResolver overloadingConflictResolver; + private final DataFlowInfo dataFlowInfo; - public CallResolver(JetSemanticServices semanticServices, JetTypeInferrer typeInferrer) { + public CallResolver(JetSemanticServices semanticServices, JetTypeInferrer typeInferrer, DataFlowInfo dataFlowInfo) { this.typeInferrer = typeInferrer; this.semanticServices = semanticServices; this.overloadingConflictResolver = new OverloadingConflictResolver(semanticServices); + this.dataFlowInfo = dataFlowInfo; } @Nullable @@ -54,7 +57,7 @@ public class CallResolver { return null; } Call call = CallMaker.makePropertyCall(nameExpression); - List> prioritizedTasks = PROPERTY_TASK_PRIORITIZER.computePrioritizedTasks(scope, receiver, call, referencedName); + List> prioritizedTasks = TaskPrioritizers.PROPERTY_TASK_PRIORITIZER.computePrioritizedTasks(scope, receiver, call, referencedName, trace.getBindingContext(), dataFlowInfo); return resolveCallToDescriptor(trace, scope, call, nameExpression.getNode(), expectedType, prioritizedTasks, nameExpression); } @@ -80,9 +83,7 @@ public class CallResolver { @NotNull String name, @NotNull ReceiverDescriptor receiver, @NotNull JetType expectedType) { - // TODO : autocasts - // TODO : nullability - List> tasks = FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, receiver, call, name); + List> tasks = TaskPrioritizers.FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, receiver, call, name, trace.getBindingContext(), dataFlowInfo); return resolveCallToDescriptor(trace, scope, call, functionReference.getNode(), expectedType, tasks, functionReference); } @@ -105,7 +106,7 @@ public class CallResolver { String name = expression.getReferencedName(); if (name == null) return checkArgumentTypesAndFail(trace, scope, call); - prioritizedTasks = FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, receiver, call, name); + prioritizedTasks = TaskPrioritizers.FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, receiver, call, name, trace.getBindingContext(), dataFlowInfo); ResolutionTask.DescriptorCheckStrategy abstractConstructorCheck = new ResolutionTask.DescriptorCheckStrategy() { @Override public boolean performAdvancedChecks(D descriptor, BindingTrace trace, TracingStrategy tracing) { @@ -128,7 +129,7 @@ public class CallResolver { JetValueArgumentList valueArgumentList = call.getValueArgumentList(); ASTNode reportAbsenceOn = valueArgumentList == null ? call.getNode() : valueArgumentList.getNode(); if (calleeExpression instanceof JetConstructorCalleeExpression) { - assert receiver == NO_RECEIVER; + assert !receiver.exists(); prioritizedTasks = Lists.newArrayList(); @@ -149,7 +150,7 @@ public class CallResolver { trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn)); return checkArgumentTypesAndFail(trace, scope, call); } - prioritizedTasks.add(new ResolutionTask(constructors, NO_RECEIVER, call)); + prioritizedTasks.add(new ResolutionTask(ResolvedCall.convertCollection(constructors), NO_RECEIVER, call)); } else { // trace.getErrorHandler().genericError(calleeExpression.getNode(), "Not a class"); @@ -163,14 +164,13 @@ public class CallResolver { assert containingDeclaration instanceof ClassDescriptor; ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; - Set constructors = classDescriptor.getConstructors(); if (constructors.isEmpty()) { // trace.getErrorHandler().genericError(reportAbsenceOn, "This class does not have a constructor"); trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn)); return checkArgumentTypesAndFail(trace, scope, call); } - prioritizedTasks = Collections.singletonList(new ResolutionTask(constructors, NO_RECEIVER, call)); + prioritizedTasks = Collections.singletonList(new ResolutionTask(ResolvedCall.convertCollection(constructors), NO_RECEIVER, call)); } else { throw new UnsupportedOperationException("Type argument inference not implemented for " + call.getText()); @@ -185,6 +185,7 @@ public class CallResolver { return null; } + @Nullable private D resolveCallToDescriptor( @NotNull BindingTrace trace, @NotNull JetScope scope, @@ -193,17 +194,38 @@ public class CallResolver { @NotNull JetType expectedType, @NotNull final List> prioritizedTasks, // high to low priority @NotNull final JetReferenceExpression reference) { + ResolvedCall resolvedCall = doResolveCall(trace, scope, call, callNode, expectedType, prioritizedTasks, reference); + return resolvedCall == null ? null : resolvedCall.getResultingDescriptor(); + } + + @Nullable + private ResolvedCall doResolveCall( + @NotNull BindingTrace trace, + @NotNull JetScope scope, + @NotNull final Call call, + @NotNull final ASTNode callNode, + @NotNull JetType expectedType, + @NotNull final List> prioritizedTasks, // high to low priority + @NotNull final JetReferenceExpression reference) { TemporaryBindingTrace traceForFirstNonemptyCandidateSet = null; - OverloadResolutionResult resultForFirstNonemptyCandidateSet = null; + OverloadResolutionResults resultsForFirstNonemptyCandidateSet = null; TracingStrategy tracing = new TracingStrategy() { @Override public void bindReference(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor receiver, @NotNull CallableDescriptor descriptor) { trace.record(REFERENCE_TARGET, reference, descriptor); trace.record(RECEIVER, reference, receiver); + if (receiver instanceof AutocastReceiver) { + AutocastReceiver autoCastReceiver = (AutocastReceiver) receiver; + ReceiverDescriptor original = autoCastReceiver.getOriginal(); + if (original instanceof ExpressionReceiver) { + ExpressionReceiver expressionReceiver = (ExpressionReceiver) original; + trace.record(AUTOCAST, expressionReceiver.getExpression(), autoCastReceiver.getType()); + } + } } @Override - public void recordAmbiguity(BindingTrace trace, Collection candidates) { + public void recordAmbiguity(BindingTrace trace, Collection> candidates) { trace.record(AMBIGUOUS_REFERENCE_TARGET, reference, candidates); } @@ -254,12 +276,12 @@ public class CallResolver { } @Override - public void ambiguity(@NotNull BindingTrace trace, @NotNull Set descriptors) { + public void ambiguity(@NotNull BindingTrace trace, @NotNull Set> descriptors) { trace.report(OVERLOAD_RESOLUTION_AMBIGUITY.on(callNode, descriptors)); } @Override - public void noneApplicable(@NotNull BindingTrace trace, @NotNull Set descriptors) { + public void noneApplicable(@NotNull BindingTrace trace, @NotNull Set> descriptors) { trace.report(NONE_APPLICABLE.on(callNode, descriptors)); } @@ -276,20 +298,20 @@ public class CallResolver { }; for (ResolutionTask task : prioritizedTasks) { TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(trace); - OverloadResolutionResult result = performResolution(temporaryTrace, scope, expectedType, task, tracing); - if (result.isSuccess()) { + OverloadResolutionResults results = performResolution(temporaryTrace, scope, expectedType, task, tracing); + if (results.isSuccess()) { temporaryTrace.commit(); - return result.getDescriptor(); + return results.getResult(); } if (traceForFirstNonemptyCandidateSet == null && !task.getCandidates().isEmpty()) { traceForFirstNonemptyCandidateSet = temporaryTrace; - resultForFirstNonemptyCandidateSet = result; + resultsForFirstNonemptyCandidateSet = results; } } if (traceForFirstNonemptyCandidateSet != null) { traceForFirstNonemptyCandidateSet.commit(); - if (resultForFirstNonemptyCandidateSet.singleDescriptor()) { - return resultForFirstNonemptyCandidateSet.getDescriptor(); + if (resultsForFirstNonemptyCandidateSet.singleDescriptor()) { + return resultsForFirstNonemptyCandidateSet.getResult(); } } else { @@ -302,45 +324,43 @@ public class CallResolver { ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @NotNull - private OverloadResolutionResult performResolution(@NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull JetType expectedType, @NotNull ResolutionTask task, @NotNull TracingStrategy tracing) { - Map successfulCandidates = Maps.newLinkedHashMap(); - Set failedCandidates = Sets.newLinkedHashSet(); - Set dirtyCandidates = Sets.newLinkedHashSet(); -// Map solutions = Maps.newHashMap(); - Map traces = Maps.newHashMap(); + private OverloadResolutionResults performResolution(@NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull JetType expectedType, @NotNull ResolutionTask task, @NotNull TracingStrategy tracing) { + Set> successfulCandidates = Sets.newLinkedHashSet(); + Set> failedCandidates = Sets.newLinkedHashSet(); + Set> dirtyCandidates = Sets.newLinkedHashSet(); - for (D candidate : task.getCandidates()) { + for (ResolvedCall candidateCall : task.getCandidates()) { + D candidate = candidateCall.getCandidateDescriptor(); TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(trace); - traces.put(candidate, temporaryTrace); - JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace); + candidateCall.setTrace(temporaryTrace); tracing.bindReference(temporaryTrace, task.getReceiver(), candidate); if (ErrorUtils.isError(candidate)) { - successfulCandidates.put(candidate, candidate); + successfulCandidates.add(candidateCall.setResultingDescriptor(candidate)); checkTypesWithNoCallee(temporaryTrace, scope, task.getTypeArguments(), task.getValueArguments(), task.getFunctionLiteralArguments()); continue; } - Ref dirty = new Ref(false); Map argumentsToParameters = Maps.newHashMap(); boolean error = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(task, tracing, candidate, temporaryTrace, argumentsToParameters); if (error) { - failedCandidates.add(candidate); + failedCandidates.add(candidateCall); checkTypesWithNoCallee(temporaryTrace, scope, task.getTypeArguments(), task.getValueArguments(), task.getFunctionLiteralArguments()); continue; } + Ref dirty = new Ref(false); if (task.getTypeArguments().isEmpty()) { if (candidate.getTypeParameters().isEmpty()) { - if (checkValueArgumentTypes(scope, temporaryServices, argumentsToParameters, dirty, Functions.identity()) + if (checkValueArgumentTypes(scope, temporaryTrace, argumentsToParameters, dirty, Functions.identity()) && checkReceiver(task, tracing, candidate, temporaryTrace)) { - successfulCandidates.put(candidate, candidate); + successfulCandidates.add(candidateCall.setResultingDescriptor(candidate)); } else { - failedCandidates.add(candidate); + failedCandidates.add(candidateCall); } } else { @@ -357,6 +377,7 @@ public class CallResolver { JetExpression expression = valueArgument.getArgumentExpression(); // TODO : more attempts, with different expected types + JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace); JetType type = temporaryServices.getType(scope, expression, NO_EXPECTED_TYPE); if (type != null) { constraintSystem.addSubtypingConstraint(type, valueParameterDescriptor.getOutType()); @@ -370,7 +391,7 @@ public class CallResolver { // Error is already reported if something is missing ReceiverDescriptor receiver = task.getReceiver(); ReceiverDescriptor candidateReceiver = candidate.getReceiver(); - if (receiver != NO_RECEIVER && candidateReceiver != NO_RECEIVER) { + if (receiver.exists() && candidateReceiver.exists()) { constraintSystem.addSubtypingConstraint(receiver.getType(), candidateReceiver.getType()); } @@ -383,11 +404,11 @@ public class CallResolver { if (solution.isSuccessful()) { D substitute = (D) candidate.substitute(solution.getSubstitutor()); assert substitute != null; - successfulCandidates.put(candidate, substitute); + successfulCandidates.add(candidateCall.setResultingDescriptor(substitute)); } else { tracing.typeInferenceFailed(temporaryTrace); - failedCandidates.add(candidate); + failedCandidates.add(candidateCall); } } } @@ -420,32 +441,32 @@ public class CallResolver { D substitutedFunctionDescriptor = (D) candidate.substitute(TypeSubstitutor.create(substitutionContext)); Function mapFunction = createMapFunction(substitutedFunctionDescriptor); - if (checkValueArgumentTypes(scope, temporaryServices, argumentsToParameters, dirty, mapFunction) + if (checkValueArgumentTypes(scope, temporaryTrace, argumentsToParameters, dirty, mapFunction) && checkReceiver(task, tracing, substitutedFunctionDescriptor, temporaryTrace)) { - successfulCandidates.put(candidate, substitutedFunctionDescriptor); + successfulCandidates.add(candidateCall.setResultingDescriptor(substitutedFunctionDescriptor)); } else { - failedCandidates.add(candidate); + failedCandidates.add(candidateCall); } } else { - failedCandidates.add(candidate); + failedCandidates.add(candidateCall); // tracing.reportWrongTypeArguments(temporaryTrace, "Number of type arguments does not match " + DescriptorRenderer.TEXT.render(candidate)); tracing.wrongNumberOfTypeArguments(temporaryTrace, expectedTypeArgumentCount); } } if (dirty.get()) { - dirtyCandidates.add(candidate); + dirtyCandidates.add(candidateCall); } task.performAdvancedChecks(candidate, temporaryTrace, tracing); } - OverloadResolutionResult result = computeResultAndReportErrors(trace, tracing, successfulCandidates, failedCandidates, dirtyCandidates, traces); - if (!result.singleDescriptor()) { + OverloadResolutionResults results = computeResultAndReportErrors(trace, tracing, successfulCandidates, failedCandidates, dirtyCandidates); + if (!results.singleDescriptor()) { checkTypesWithNoCallee(trace, scope, task.getTypeArguments(), task.getValueArguments(), task.getFunctionLiteralArguments()); } - return result; + return results; } private void checkTypesWithNoCallee(BindingTrace trace, JetScope scope, List typeArguments, List valueArguments, List functionLiteralArguments) { @@ -484,8 +505,8 @@ public class CallResolver { if (!checkReceiverAbsence(task, tracing, candidate, temporaryTrace)) return false; ReceiverDescriptor receiver = task.getReceiver(); ReceiverDescriptor candidateReceiver = candidate.getReceiver(); - if (receiver != NO_RECEIVER - && candidateReceiver != NO_RECEIVER + if (receiver.exists() + && candidateReceiver.exists() && !semanticServices.getTypeChecker().isSubtypeOf(receiver.getType(), candidateReceiver.getType())) { tracing.missingReceiver(temporaryTrace, candidateReceiver); return false; @@ -496,13 +517,13 @@ public class CallResolver { private boolean checkReceiverAbsence(ResolutionTask task, TracingStrategy tracing, D candidate, TemporaryBindingTrace temporaryTrace) { ReceiverDescriptor receiver = task.getReceiver(); ReceiverDescriptor candidateReceiver = candidate.getReceiver(); - if (receiver != NO_RECEIVER) { - if (candidateReceiver == NO_RECEIVER) { + if (receiver.exists()) { + if (!candidateReceiver.exists()) { tracing.noReceiverAllowed(temporaryTrace); return false; } } - else if (candidateReceiver != NO_RECEIVER) { + else if (candidateReceiver.exists()) { tracing.missingReceiver(temporaryTrace, candidateReceiver); return false; } @@ -510,26 +531,31 @@ public class CallResolver { } @NotNull - private OverloadResolutionResult computeResultAndReportErrors(BindingTrace trace, TracingStrategy tracing, Map successfulCandidates, Set failedCandidates, Set dirtyCandidates, Map traces) { + private OverloadResolutionResults computeResultAndReportErrors( + BindingTrace trace, + TracingStrategy tracing, + Set> successfulCandidates, // original -> substituted + Set> failedCandidates, + Set> dirtyCandidates) { // TODO : maybe it's better to filter overrides out first, and only then look for the maximally specific if (successfulCandidates.size() > 0) { if (successfulCandidates.size() != 1) { - Map cleanCandidates = Maps.newLinkedHashMap(successfulCandidates); - cleanCandidates.keySet().removeAll(dirtyCandidates); + Set> cleanCandidates = Sets.newLinkedHashSet(successfulCandidates); + cleanCandidates.removeAll(dirtyCandidates); if (cleanCandidates.isEmpty()) { cleanCandidates = successfulCandidates; } - D maximallySpecific = overloadingConflictResolver.findMaximallySpecific(cleanCandidates, traces, false); + ResolvedCall maximallySpecific = overloadingConflictResolver.findMaximallySpecific(cleanCandidates, false); if (maximallySpecific != null) { - return OverloadResolutionResult.success(maximallySpecific); + return OverloadResolutionResults.success(maximallySpecific); } - D maximallySpecificGenericsDiscriminated = overloadingConflictResolver.findMaximallySpecific(cleanCandidates, traces, true); + ResolvedCall maximallySpecificGenericsDiscriminated = overloadingConflictResolver.findMaximallySpecific(cleanCandidates, true); if (maximallySpecificGenericsDiscriminated != null) { - return OverloadResolutionResult.success(maximallySpecificGenericsDiscriminated); + return OverloadResolutionResults.success(maximallySpecificGenericsDiscriminated); } - Set noOverrides = OverridingUtil.filterOverrides(successfulCandidates.keySet()); + Set> noOverrides = OverridingUtil.filterOverrides(successfulCandidates, MAP_TO_RESULT); if (dirtyCandidates.isEmpty()) { // tracing.reportOverallResolutionError(trace, "Overload resolution ambiguity: " // + makeErrorMessageForMultipleDescriptors(noOverrides)); @@ -538,42 +564,44 @@ public class CallResolver { tracing.recordAmbiguity(trace, noOverrides); - return OverloadResolutionResult.ambiguity(noOverrides); + return OverloadResolutionResults.ambiguity(noOverrides); } else { - Map.Entry entry = successfulCandidates.entrySet().iterator().next(); - D functionDescriptor = entry.getKey(); - D result = entry.getValue(); + ResolvedCall result = successfulCandidates.iterator().next(); - TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor); + TemporaryBindingTrace temporaryTrace = result.getTrace(); temporaryTrace.commit(); - return OverloadResolutionResult.success(result); + return OverloadResolutionResults.success(result); } } else if (!failedCandidates.isEmpty()) { if (failedCandidates.size() != 1) { - Set noOverrides = OverridingUtil.filterOverrides(failedCandidates); + Set> noOverrides = OverridingUtil.filterOverrides(failedCandidates, MAP_TO_CANDIDATE); if (noOverrides.size() != 1) { // tracing.reportOverallResolutionError(trace, "None of the following functions can be called with the arguments supplied: " // + makeErrorMessageForMultipleDescriptors(noOverrides)); tracing.noneApplicable(trace, noOverrides); tracing.recordAmbiguity(trace, noOverrides); - return OverloadResolutionResult.manyFailedCandidates(noOverrides); + return OverloadResolutionResults.manyFailedCandidates(noOverrides); } failedCandidates = noOverrides; } - D functionDescriptor = failedCandidates.iterator().next(); - TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor); - temporaryTrace.commit(); - return OverloadResolutionResult.singleFailedCandidate(failedCandidates.iterator().next()); + ResolvedCall failed = failedCandidates.iterator().next(); + failed.getTrace().commit(); + return OverloadResolutionResults.singleFailedCandidate(failed); } else { tracing.unresolvedReference(trace); - return OverloadResolutionResult.nameNotFound(); + return OverloadResolutionResults.nameNotFound(); } } - private boolean checkValueArgumentTypes(JetScope scope, JetTypeInferrer.Services temporaryServices, Map argumentsToParameters, Ref dirty, Function parameterMap) { + private boolean checkValueArgumentTypes( + JetScope scope, + BindingTrace temporaryTrace, + Map argumentsToParameters, + Ref dirty, + Function parameterMap) { boolean result = true; for (Map.Entry entry : argumentsToParameters.entrySet()) { ValueArgument valueArgument = entry.getKey(); @@ -586,12 +614,34 @@ public class CallResolver { JetType parameterType = substitutedParameter.getOutType(); JetExpression argumentExpression = valueArgument.getArgumentExpression(); if (argumentExpression != null) { + JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace); JetType type = temporaryServices.getType(scope, argumentExpression, parameterType); if (type == null) { dirty.set(true); } else if (!semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) { - result = false; +// VariableDescriptor variableDescriptor = AutoCastUtils.getVariableDescriptorFromSimpleName(temporaryTrace.getBindingContext(), argumentExpression); +// if (variableDescriptor != null) { +// JetType autoCastType = null; +// for (JetType possibleType : dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)) { +// if (semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) { +// autoCastType = possibleType; +// break; +// } +// } +// if (autoCastType != null) { +// if (AutoCastUtils.isAutocastable(variableDescriptor)) { +// temporaryTrace.record(AUTOCAST, argumentExpression, autoCastType); +// } +// else { +// temporaryTrace.report(AUTOCAST_IMPOSSIBLE.on(argumentExpression, autoCastType, variableDescriptor)); +// result = false; +// } +// } +// } +// else { + result = false; +// } } } } @@ -618,23 +668,23 @@ public class CallResolver { } @NotNull - public OverloadResolutionResult resolveExactSignature(@NotNull JetScope scope, @NotNull ReceiverDescriptor receiver, @NotNull String name, @NotNull List parameterTypes) { + public OverloadResolutionResults resolveExactSignature(@NotNull JetScope scope, @NotNull ReceiverDescriptor receiver, @NotNull String name, @NotNull List parameterTypes) { List result = findCandidatesByExactSignature(scope, receiver, name, parameterTypes); BindingTraceContext trace = new BindingTraceContext(); TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create(trace); - Map traces = Maps.newHashMap(); - Map candidates = Maps.newLinkedHashMap(); + Set> candidates = Sets.newLinkedHashSet(); for (FunctionDescriptor functionDescriptor : result) { - candidates.put(functionDescriptor, functionDescriptor); - traces.put(functionDescriptor, temporaryBindingTrace); + ResolvedCall resolvedCall = ResolvedCall.create(functionDescriptor); + candidates.add(resolvedCall.setResultingDescriptor(functionDescriptor)); + resolvedCall.setTrace(temporaryBindingTrace); } - return computeResultAndReportErrors(trace, TracingStrategy.EMPTY, candidates, Collections.emptySet(), Collections.emptySet(), traces); + return computeResultAndReportErrors(trace, TracingStrategy.EMPTY, candidates, Collections.>emptySet(), Collections.>emptySet()); } private List findCandidatesByExactSignature(JetScope scope, ReceiverDescriptor receiver, String name, List parameterTypes) { List result = Lists.newArrayList(); - if (receiver != NO_RECEIVER) { + if (receiver.exists()) { Set extensionFunctionDescriptors = scope.getFunctions(name); List nonlocal = Lists.newArrayList(); List local = Lists.newArrayList(); @@ -662,7 +712,7 @@ public class CallResolver { private boolean lookupExactSignature(Set candidates, List parameterTypes, List result) { boolean found = false; for (FunctionDescriptor functionDescriptor : candidates) { - if (functionDescriptor.getReceiver() != NO_RECEIVER) continue; + if (functionDescriptor.getReceiver().exists()) continue; if (!functionDescriptor.getTypeParameters().isEmpty()) continue; if (!checkValueParameters(functionDescriptor, parameterTypes)) continue; result.add(functionDescriptor); @@ -675,7 +725,7 @@ public class CallResolver { boolean found = false; for (FunctionDescriptor functionDescriptor : candidates) { ReceiverDescriptor functionReceiver = functionDescriptor.getReceiver(); - if (functionReceiver == NO_RECEIVER) continue; + if (!functionReceiver.exists()) continue; if (!functionDescriptor.getTypeParameters().isEmpty()) continue; if (!semanticServices.getTypeChecker().isSubtypeOf(receiver.getType(), functionReceiver.getType())) continue; if (!checkValueParameters(functionDescriptor, parameterTypes))continue; @@ -695,113 +745,4 @@ public class CallResolver { } return true; } - - private static TaskPrioritizer FUNCTION_TASK_PRIORITIZER = new TaskPrioritizer() { - - @NotNull - @Override - protected Collection getNonExtensionsByName(JetScope scope, String name) { - Set functions = Sets.newLinkedHashSet(scope.getFunctions(name)); - for (Iterator iterator = functions.iterator(); iterator.hasNext(); ) { - FunctionDescriptor functionDescriptor = iterator.next(); - if (functionDescriptor.getReceiver() != NO_RECEIVER) { - iterator.remove(); - } - } - addConstructors(scope, name, functions); - - addVariableAsFunction(scope, name, functions, false); - return functions; - } - - @NotNull - @Override - protected Collection getMembersByName(@NotNull ReceiverDescriptor receiver, String name) { - JetScope receiverScope = receiver.getType().getMemberScope(); - Set members = Sets.newHashSet(receiverScope.getFunctions(name)); - addConstructors(receiverScope, name, members); - addVariableAsFunction(receiverScope, name, members, false); - return members; - } - - @NotNull - @Override - protected Collection getExtensionsByName(JetScope scope, String name) { - Set extensionFunctions = Sets.newHashSet(scope.getFunctions(name)); - for (Iterator iterator = extensionFunctions.iterator(); iterator.hasNext(); ) { - FunctionDescriptor descriptor = iterator.next(); - if (descriptor.getReceiver() == NO_RECEIVER) { - iterator.remove(); - } - } - addVariableAsFunction(scope, name, extensionFunctions, true); - return extensionFunctions; - } - - @NotNull - @Override - protected ResolutionTask createTask(@NotNull ReceiverDescriptor receiver, Call call, Collection candidates) { - return new ResolutionTask(candidates, receiver, call); - } - - private void addConstructors(JetScope scope, String name, Collection functions) { - ClassifierDescriptor classifier = scope.getClassifier(name); - if (classifier instanceof ClassDescriptor && !ErrorUtils.isError(classifier.getTypeConstructor())) { - ClassDescriptor classDescriptor = (ClassDescriptor) classifier; - functions.addAll(classDescriptor.getConstructors()); - } - } - - private void addVariableAsFunction(JetScope scope, String name, Set functions, boolean receiverNeeded) { - VariableDescriptor variable = scope.getVariable(name); - if (variable != null && variable.getReceiver() == NO_RECEIVER) { - JetType outType = variable.getOutType(); - if (outType != null && JetStandardClasses.isFunctionType(outType)) { - VariableAsFunctionDescriptor functionDescriptor = VariableAsFunctionDescriptor.create(variable); - if ((functionDescriptor.getReceiver() != NO_RECEIVER) == receiverNeeded) { - functions.add(functionDescriptor); - } - } - } - } - }; - - private static TaskPrioritizer PROPERTY_TASK_PRIORITIZER = new TaskPrioritizer() { - - @NotNull - @Override - protected Collection getNonExtensionsByName(JetScope scope, String name) { - VariableDescriptor variable = scope.getVariable(name); - if (variable != null && variable.getReceiver() == NO_RECEIVER) { - return Collections.singleton(variable); - } - return Collections.emptyList(); - } - - @NotNull - @Override - protected Collection getMembersByName(@NotNull ReceiverDescriptor receiver, String name) { - VariableDescriptor variable = receiver.getType().getMemberScope().getVariable(name); - if (variable != null) { - return Collections.singleton(variable); - } - return Collections.emptyList(); - } - - @NotNull - @Override - protected Collection getExtensionsByName(JetScope scope, String name) { - VariableDescriptor variable = scope.getVariable(name); - if (variable != null && variable.getReceiver() != NO_RECEIVER) { - return Collections.singleton(variable); - } - return Collections.emptyList(); - } - - @NotNull - @Override - protected ResolutionTask createTask(@NotNull ReceiverDescriptor receiver, Call call, Collection candidates) { - return new ResolutionTask(candidates, receiver, call); - } - }; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadResolutionResult.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadResolutionResult.java deleted file mode 100644 index 799d001616b..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadResolutionResult.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.jetbrains.jet.lang.resolve.calls; - -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; -import java.util.Collections; -import java.util.Set; - -/** -* @author abreslav -*/ -public class OverloadResolutionResult { - public enum Code { - SUCCESS(true), - NAME_NOT_FOUND(false), - SINGLE_CANDIDATE_ARGUMENT_MISMATCH(false), - AMBIGUITY(false), - MANY_FAILED_CANDIDATES(false); - - private final boolean success; - - Code(boolean success) { - this.success = success; - } - - boolean isSuccess() { - return success; - } - - } - - public static OverloadResolutionResult success(@NotNull D descriptor) { - return new OverloadResolutionResult(Code.SUCCESS, Collections.singleton(descriptor)); - } - - public static OverloadResolutionResult nameNotFound() { - return new OverloadResolutionResult(Code.NAME_NOT_FOUND, Collections.emptyList()); - } - - public static OverloadResolutionResult singleFailedCandidate(D candidate) { - return new OverloadResolutionResult(Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH, Collections.singleton(candidate)); - } - public static OverloadResolutionResult manyFailedCandidates(Set failedCandidates) { - return new OverloadResolutionResult(Code.MANY_FAILED_CANDIDATES, failedCandidates); - } - - public static OverloadResolutionResult ambiguity(Collection descriptors) { - return new OverloadResolutionResult(Code.AMBIGUITY, descriptors); - } - - private final Collection descriptors; - - private final Code resultCode; - - public OverloadResolutionResult(@NotNull Code resultCode, @NotNull Collection descriptors) { - this.descriptors = descriptors; - this.resultCode = resultCode; - - } - - @NotNull - public Collection getDescriptors() { - return descriptors; - } - - @NotNull - public D getDescriptor() { - assert singleDescriptor(); - return descriptors.iterator().next(); - } - - @NotNull - public Code getResultCode() { - return resultCode; - } - - public boolean isSuccess() { - return resultCode.isSuccess(); - } - - public boolean singleDescriptor() { - return isSuccess() || resultCode == Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH; - } - - public boolean isNothing() { - return resultCode == Code.NAME_NOT_FOUND; - } - - public boolean isAmbiguity() { - return resultCode == Code.AMBIGUITY; - } - - public OverloadResolutionResult newContents(@NotNull Collection functionDescriptors) { - return new OverloadResolutionResult(resultCode, functionDescriptors); - } -} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadResolutionResults.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadResolutionResults.java new file mode 100644 index 00000000000..034c7447d89 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadResolutionResults.java @@ -0,0 +1,95 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.CallableDescriptor; + +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +/** +* @author abreslav +*/ +public class OverloadResolutionResults { + public enum Code { + SUCCESS(true), + NAME_NOT_FOUND(false), + SINGLE_CANDIDATE_ARGUMENT_MISMATCH(false), + AMBIGUITY(false), + MANY_FAILED_CANDIDATES(false); + + private final boolean success; + + Code(boolean success) { + this.success = success; + } + + boolean isSuccess() { + return success; + } + + } + + public static OverloadResolutionResults success(@NotNull ResolvedCall descriptor) { + return new OverloadResolutionResults(Code.SUCCESS, Collections.singleton(descriptor)); + } + + public static OverloadResolutionResults nameNotFound() { + return new OverloadResolutionResults(Code.NAME_NOT_FOUND, Collections.>emptyList()); + } + + public static OverloadResolutionResults singleFailedCandidate(ResolvedCall candidate) { + return new OverloadResolutionResults(Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH, Collections.singleton(candidate)); + } + public static OverloadResolutionResults manyFailedCandidates(Set> failedCandidates) { + return new OverloadResolutionResults(Code.MANY_FAILED_CANDIDATES, failedCandidates); + } + + public static OverloadResolutionResults ambiguity(Collection> descriptors) { + return new OverloadResolutionResults(Code.AMBIGUITY, descriptors); + } + + private final Collection> results; + private final Code resultCode; + + private OverloadResolutionResults(@NotNull Code resultCode, @NotNull Collection> results) { + this.results = results; + this.resultCode = resultCode; + } + + @NotNull + public Collection> getResults() { + return results; + } + + @NotNull + public ResolvedCall getResult() { + assert singleDescriptor(); + return results.iterator().next(); + } + + @NotNull + public Code getResultCode() { + return resultCode; + } + + public boolean isSuccess() { + return resultCode.isSuccess(); + } + + public boolean singleDescriptor() { + return isSuccess() || resultCode == Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH; + } + + public boolean isNothing() { + return resultCode == Code.NAME_NOT_FOUND; + } + + public boolean isAmbiguity() { + return resultCode == Code.AMBIGUITY; + } +// +// public OverloadResolutionResults newContents(@NotNull Collection functionDescriptors) { +// return new OverloadResolutionResults(resultCode, functionDescriptors); +// } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java index 127cf37efec..bf729832db2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java @@ -1,6 +1,6 @@ package org.jetbrains.jet.lang.resolve.calls; -import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.JetSemanticServices; @@ -8,13 +8,12 @@ import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.OverridingUtil; -import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.JetStandardLibrary; import org.jetbrains.jet.lang.types.JetType; import java.util.List; -import java.util.Map; +import java.util.Set; /** * @author abreslav @@ -28,22 +27,24 @@ public class OverloadingConflictResolver { } @Nullable - public Descriptor findMaximallySpecific(Map candidates, Map traces, boolean discriminateGenericDescriptors) { - Map maximallySpecific = Maps.newHashMap(); + public ResolvedCall findMaximallySpecific(Set> candidates, boolean discriminateGenericDescriptors) { + Set> maximallySpecific = Sets.newHashSet(); meLoop: - for (Map.Entry myEntry : candidates.entrySet()) { - Descriptor me = myEntry.getValue(); - TemporaryBindingTrace myTrace = traces.get(myEntry.getKey()); - for (Descriptor other : candidates.values()) { + for (ResolvedCall candidateCall : candidates) { + D me = candidateCall.getResultingDescriptor(); + for (ResolvedCall otherCall : candidates) { + D other = otherCall.getResultingDescriptor(); if (other == me) continue; - if (!moreSpecific(me, other, discriminateGenericDescriptors) || moreSpecific(other, me, discriminateGenericDescriptors)) continue meLoop; + if (!moreSpecific(me, other, discriminateGenericDescriptors) || moreSpecific(other, me, discriminateGenericDescriptors)) { + continue meLoop; + } } - maximallySpecific.put(me, myTrace); + maximallySpecific.add(candidateCall); } if (maximallySpecific.size() == 1) { - Map.Entry result = maximallySpecific.entrySet().iterator().next(); - result.getValue().commit(); - return result.getKey(); + ResolvedCall result = maximallySpecific.iterator().next(); + result.getTrace().commit(); + return result; } return null; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java index c369d8aa730..b9560678fba 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java @@ -1,7 +1,6 @@ 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; @@ -9,7 +8,6 @@ import org.jetbrains.jet.lang.psi.JetTypeProjection; import org.jetbrains.jet.lang.psi.ValueArgument; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; -import org.jetbrains.jet.lang.types.JetType; import java.util.Collection; import java.util.List; @@ -17,8 +15,8 @@ import java.util.List; /** * @author abreslav */ -/*package*/ class ResolutionTask { - private final Collection candidates; +/*package*/ class ResolutionTask { + private final Collection> candidates; private final ReceiverDescriptor receiver; private final List typeArguments; private final List valueArguments; @@ -26,7 +24,7 @@ import java.util.List; private DescriptorCheckStrategy checkingStrategy; public ResolutionTask( - @NotNull Collection candidates, + @NotNull Collection> candidates, @NotNull ReceiverDescriptor receiver, @NotNull List typeArguments, @NotNull List valueArguments, @@ -39,7 +37,7 @@ import java.util.List; } public ResolutionTask( - @NotNull Collection candidates, + @NotNull Collection> candidates, @NotNull ReceiverDescriptor receiver, @NotNull Call call ) { @@ -47,7 +45,7 @@ import java.util.List; } @NotNull - public Collection getCandidates() { + public Collection> getCandidates() { return candidates; } @@ -75,7 +73,7 @@ import java.util.List; checkingStrategy = strategy; } - public boolean performAdvancedChecks(Descriptor descriptor, BindingTrace trace, TracingStrategy tracing) { + public boolean performAdvancedChecks(D descriptor, BindingTrace trace, TracingStrategy tracing) { if (checkingStrategy != null && !checkingStrategy.performAdvancedChecks(descriptor, trace, tracing)) { return false; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java new file mode 100644 index 00000000000..b18d967ecf6 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java @@ -0,0 +1,122 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.intellij.util.Function; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.CallableDescriptor; +import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; +import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; +import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.types.JetType; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * @author abreslav + */ +public class ResolvedCall { + + public static final Function, CallableDescriptor> MAP_TO_CANDIDATE = new Function, CallableDescriptor>() { + @Override + public CallableDescriptor fun(ResolvedCall resolvedCall) { + return resolvedCall.getCandidateDescriptor(); + } + }; + + public static final Function, CallableDescriptor> MAP_TO_RESULT = new Function, CallableDescriptor>() { + @Override + public CallableDescriptor fun(ResolvedCall resolvedCall) { + return resolvedCall.getResultingDescriptor(); + } + }; + + @NotNull + public static ResolvedCall create(@NotNull D descriptor) { + return new ResolvedCall(descriptor); + } + + @NotNull + public static List> convertCollection(@NotNull Collection descriptors) { + List> result = Lists.newArrayList(); + for (D descriptor : descriptors) { + result.add(create(descriptor)); + } + return result; + } + + private final D candidateDescriptor; + private D resultingDescriptor; // Probably substituted + private ReceiverDescriptor thisObject; // receiver object of a method + private ReceiverDescriptor receiverParameter; // receiver of an extension function + private final Map typeArguments = Maps.newHashMap(); + private final Map autoCasts = Maps.newHashMap(); + private final Map valueArguments = Maps.newHashMap(); + private TemporaryBindingTrace trace; + + private ResolvedCall(@NotNull D candidateDescriptor) { + this.candidateDescriptor = candidateDescriptor; + } + + @NotNull + public TemporaryBindingTrace getTrace() { + return trace; + } + + public void setTrace(@NotNull TemporaryBindingTrace trace) { + this.trace = trace; + } + + @NotNull + public D getCandidateDescriptor() { + return candidateDescriptor; + } + + @NotNull + public D getResultingDescriptor() { + return resultingDescriptor == null ? candidateDescriptor : resultingDescriptor; + } + + public ResolvedCall setResultingDescriptor(@NotNull D resultingDescriptor) { + this.resultingDescriptor = resultingDescriptor; + return this; + } + + public void recordTypeArgument(@NotNull TypeParameterDescriptor typeParameter, @NotNull JetType typeArgument) { + assert !typeArguments.containsKey(typeParameter); + typeArguments.put(typeParameter, typeArgument); + } + + public void recordValueArgument(@NotNull ValueParameterDescriptor valueParameter, @NotNull ResolvedValueArgument valueArgument) { + assert !valueArguments.containsKey(valueParameter); + valueArguments.put(valueParameter, valueArgument); + } + + public void autoCastValueArgument(@NotNull ValueParameterDescriptor parameter, @NotNull JetType target) { + assert !autoCasts.containsKey(parameter); + autoCasts.put(parameter, target); + } + + @Nullable + public ReceiverDescriptor getReceiverParameter() { + return receiverParameter; + } + + public void setReceiverParameter(@NotNull ReceiverDescriptor receiverParameter) { + this.receiverParameter = receiverParameter; + } + + @Nullable + public ReceiverDescriptor getThisObject() { + return thisObject; + } + + public void setThisObject(@NotNull ReceiverDescriptor thisObject) { + this.thisObject = thisObject; + } + +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedValueArgument.java new file mode 100644 index 00000000000..4f3216e8a91 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedValueArgument.java @@ -0,0 +1,8 @@ +package org.jetbrains.jet.lang.resolve.calls; + +/** +* @author abreslav +*/ +public interface ResolvedValueArgument { + +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java index c14a3c00e9e..a71578341df 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java @@ -2,17 +2,21 @@ package org.jetbrains.jet.lang.resolve.calls; import com.google.common.collect.Lists; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.CallableDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.psi.Call; -import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.types.DataFlowInfo; import java.util.Collection; import java.util.List; +import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER; + /** * @author abreslav */ @@ -62,16 +66,30 @@ import java.util.List; return false; } - public List> computePrioritizedTasks(@NotNull JetScope scope, @NotNull ReceiverDescriptor receiver, @NotNull Call call, @NotNull String name) { +// public List> computePrioritizedTasks(@NotNull JetScope scope, @NotNull ReceiverDescriptor receiver, @NotNull Call call, @NotNull String name) { +// List> result = Lists.newArrayList(); +// doComputeTasks(scope, receiver, call, name, result); +// return result; +// } + + public List> computePrioritizedTasks(@NotNull JetScope scope, @NotNull ReceiverDescriptor receiver, @NotNull Call call, @NotNull String name, @NotNull BindingContext bindingContext, @NotNull DataFlowInfo dataFlowInfo) { List> result = Lists.newArrayList(); + doComputeTasks(scope, receiver, call, name, result); + +// ReceiverDescriptor receiverToCast = receiver.exists() ? receiver : scope.getImplicitReceiver(); +// if (receiverToCast.exists()) { +// for (ReceiverDescriptor castReceiver : AutoCastUtils.getAutocastVariants(bindingContext, dataFlowInfo, receiverToCast)) { +// doComputeTasks(scope, castReceiver, call, name, result); +// } +// } return result; } private void doComputeTasks(JetScope scope, ReceiverDescriptor receiver, Call call, String name, List> result) { List implicitReceivers = Lists.newArrayList(); scope.getImplicitReceiversHierarchy(implicitReceivers); - if (receiver != ReceiverDescriptor.NO_RECEIVER) { + if (receiver.exists()) { Collection extensionFunctions = getExtensionsByName(scope, name); List nonlocals = Lists.newArrayList(); List locals = Lists.newArrayList(); @@ -81,7 +99,7 @@ import java.util.List; Collection members = getMembersByName(receiver, name); addTask(result, receiver, call, locals); - addTask(result, ReceiverDescriptor.NO_RECEIVER, call, members); + addTask(result, NO_RECEIVER, call, members); for (ReceiverDescriptor implicitReceiver : implicitReceivers) { Collection memberExtensions = getExtensionsByName(implicitReceiver.getType().getMemberScope(), name); @@ -108,6 +126,11 @@ import java.util.List; } } + private void addTask(@NotNull List> result, @NotNull ReceiverDescriptor receiver, @NotNull Call call, @NotNull Collection candidateDescriptors) { + if (candidateDescriptors.isEmpty()) return; + result.add(createTask(receiver, call, ResolvedCall.convertCollection(candidateDescriptors))); + } + @NotNull protected abstract Collection getNonExtensionsByName(JetScope scope, String name); @@ -117,12 +140,7 @@ import java.util.List; @NotNull protected abstract Collection getExtensionsByName(JetScope scope, String name); - private void addTask(@NotNull List> result, @NotNull ReceiverDescriptor receiver, @NotNull Call call, @NotNull Collection candidates) { - if (candidates.isEmpty()) return; - result.add(createTask(receiver, call, candidates)); - } - @NotNull - protected abstract ResolutionTask createTask(ReceiverDescriptor receiver, Call call, Collection candidates); + protected abstract ResolutionTask createTask(ReceiverDescriptor receiver, Call call, Collection> candidates); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizers.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizers.java new file mode 100644 index 00000000000..fce2259c2a2 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizers.java @@ -0,0 +1,132 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import com.google.common.collect.Sets; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.Call; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.types.ErrorUtils; +import org.jetbrains.jet.lang.types.JetStandardClasses; +import org.jetbrains.jet.lang.types.JetType; + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.Set; + +/** + * @author abreslav + */ +public class TaskPrioritizers { + + + /*package*/ static TaskPrioritizer FUNCTION_TASK_PRIORITIZER = new TaskPrioritizer() { + + @NotNull + @Override + protected Collection getNonExtensionsByName(JetScope scope, String name) { + Set functions = Sets.newLinkedHashSet(scope.getFunctions(name)); + for (Iterator iterator = functions.iterator(); iterator.hasNext(); ) { + FunctionDescriptor functionDescriptor = iterator.next(); + if (functionDescriptor.getReceiver().exists()) { + iterator.remove(); + } + } + addConstructors(scope, name, functions); + + addVariableAsFunction(scope, name, functions, false); + return functions; + } + + @NotNull + @Override + protected Collection getMembersByName(@NotNull ReceiverDescriptor receiver, String name) { + JetScope receiverScope = receiver.getType().getMemberScope(); + Set members = Sets.newHashSet(receiverScope.getFunctions(name)); + addConstructors(receiverScope, name, members); + addVariableAsFunction(receiverScope, name, members, false); + return members; + } + + @NotNull + @Override + protected Collection getExtensionsByName(JetScope scope, String name) { + Set extensionFunctions = Sets.newHashSet(scope.getFunctions(name)); + for (Iterator iterator = extensionFunctions.iterator(); iterator.hasNext(); ) { + FunctionDescriptor descriptor = iterator.next(); + if (!descriptor.getReceiver().exists()) { + iterator.remove(); + } + } + addVariableAsFunction(scope, name, extensionFunctions, true); + return extensionFunctions; + } + + @NotNull + @Override + protected ResolutionTask createTask(@NotNull ReceiverDescriptor receiver, Call call, Collection> candidates) { + return new ResolutionTask(candidates, receiver, call); + } + + private void addConstructors(JetScope scope, String name, Collection functions) { + ClassifierDescriptor classifier = scope.getClassifier(name); + if (classifier instanceof ClassDescriptor && !ErrorUtils.isError(classifier.getTypeConstructor())) { + ClassDescriptor classDescriptor = (ClassDescriptor) classifier; + functions.addAll(classDescriptor.getConstructors()); + } + } + + private void addVariableAsFunction(JetScope scope, String name, Set functions, boolean receiverNeeded) { + VariableDescriptor variable = scope.getVariable(name); + if (variable != null && !variable.getReceiver().exists()) { + JetType outType = variable.getOutType(); + if (outType != null && JetStandardClasses.isFunctionType(outType)) { + VariableAsFunctionDescriptor functionDescriptor = VariableAsFunctionDescriptor.create(variable); + if ((functionDescriptor.getReceiver().exists()) == receiverNeeded) { + functions.add(functionDescriptor); + } + } + } + } + }; + + /*package*/ static TaskPrioritizer PROPERTY_TASK_PRIORITIZER = new TaskPrioritizer() { + + @NotNull + @Override + protected Collection getNonExtensionsByName(JetScope scope, String name) { + VariableDescriptor variable = scope.getVariable(name); + if (variable != null && !variable.getReceiver().exists()) { + return Collections.singleton(variable); + } + return Collections.emptyList(); + } + + @NotNull + @Override + protected Collection getMembersByName(@NotNull ReceiverDescriptor receiver, String name) { + VariableDescriptor variable = receiver.getType().getMemberScope().getVariable(name); + if (variable != null) { + return Collections.singleton(variable); + } + return Collections.emptyList(); + } + + @NotNull + @Override + protected Collection getExtensionsByName(JetScope scope, String name) { + VariableDescriptor variable = scope.getVariable(name); + if (variable != null && variable.getReceiver().exists()) { + return Collections.singleton(variable); + } + return Collections.emptyList(); + } + + @NotNull + @Override + protected ResolutionTask createTask(@NotNull ReceiverDescriptor receiver, Call call, Collection> candidates) { + return new ResolutionTask(candidates, receiver, call); + } + }; +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java index 2429496de86..028df0226b6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java @@ -21,7 +21,7 @@ import java.util.Set; public void unresolvedReference(@NotNull BindingTrace trace) {} @Override - public void recordAmbiguity(BindingTrace trace, Collection candidates) {} + public void recordAmbiguity(BindingTrace trace, Collection> candidates) {} @Override public void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor expectedReceiver) {} @@ -36,10 +36,10 @@ import java.util.Set; public void wrongNumberOfTypeArguments(@NotNull BindingTrace trace, int expectedTypeArgumentCount) {} @Override - public void ambiguity(@NotNull BindingTrace trace, @NotNull Set descriptors) {} + public void ambiguity(@NotNull BindingTrace trace, @NotNull Set> descriptors) {} @Override - public void noneApplicable(@NotNull BindingTrace trace, @NotNull Set descriptors) {} + public void noneApplicable(@NotNull BindingTrace trace, @NotNull Set> descriptors) {} @Override public void instantiationOfAbstractClass(@NotNull BindingTrace trace) {} @@ -52,7 +52,7 @@ import java.util.Set; void unresolvedReference(@NotNull BindingTrace trace); - void recordAmbiguity(BindingTrace trace, Collection candidates); + void recordAmbiguity(BindingTrace trace, Collection> candidates); void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor expectedReceiver); @@ -62,9 +62,9 @@ import java.util.Set; void wrongNumberOfTypeArguments(@NotNull BindingTrace trace, int expectedTypeArgumentCount); - void ambiguity(@NotNull BindingTrace trace, @NotNull Set descriptors); + void ambiguity(@NotNull BindingTrace trace, @NotNull Set> descriptors); - void noneApplicable(@NotNull BindingTrace trace, @NotNull Set descriptors); + void noneApplicable(@NotNull BindingTrace trace, @NotNull Set> descriptors); void instantiationOfAbstractClass(@NotNull BindingTrace trace); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ReceiverDescriptorVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ReceiverDescriptorVisitor.java index f7ba43b15aa..1917e219255 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ReceiverDescriptorVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ReceiverDescriptorVisitor.java @@ -20,7 +20,7 @@ public class ReceiverDescriptorVisitor { return null; } - public R visitClassReceiver(ClassReceiver classReceiver, D data) { + public R visitClassReceiver(ClassReceiver receiver, D data) { return null; } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/DataFlowInfo.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/DataFlowInfo.java index 04ac9f08f6b..150fb7378f1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/DataFlowInfo.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/DataFlowInfo.java @@ -4,6 +4,7 @@ import com.google.common.collect.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.VariableDescriptor; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.util.CommonSuppliers; import java.util.*; @@ -14,9 +15,9 @@ import java.util.*; public class DataFlowInfo { public static abstract class CompositionOperator { + public abstract DataFlowInfo compose(DataFlowInfo a, DataFlowInfo b); } - public static final CompositionOperator AND = new CompositionOperator() { @Override public DataFlowInfo compose(DataFlowInfo a, DataFlowInfo b) { @@ -31,7 +32,7 @@ public class DataFlowInfo { } }; - private static DataFlowInfo EMPTY = new DataFlowInfo(ImmutableMap.of(), Multimaps.newListMultimap(Collections.>emptyMap(), CommonSuppliers.getArrayListSupplier())); + private static DataFlowInfo EMPTY = new DataFlowInfo(ImmutableMap.of(), Multimaps.newListMultimap(Collections.>emptyMap(), CommonSuppliers.getArrayListSupplier())); public static DataFlowInfo getEmpty() { return EMPTY; @@ -39,10 +40,11 @@ public class DataFlowInfo { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - private final ImmutableMap nullabilityInfo; - private final ListMultimap typeInfo; + private final ImmutableMap nullabilityInfo; - private DataFlowInfo(ImmutableMap nullabilityInfo, ListMultimap typeInfo) { + private final ListMultimap typeInfo; + + private DataFlowInfo(ImmutableMap nullabilityInfo, ListMultimap typeInfo) { this.nullabilityInfo = nullabilityInfo; this.typeInfo = typeInfo; } @@ -60,9 +62,9 @@ public class DataFlowInfo { } @NotNull - public List getPossibleTypes(VariableDescriptor variableDescriptor) { - List types = typeInfo.get(variableDescriptor); - NullabilityFlags nullabilityFlags = nullabilityInfo.get(variableDescriptor); + private List getPossibleTypes(Object key) { + List types = typeInfo.get(key); + NullabilityFlags nullabilityFlags = nullabilityInfo.get(key); if (nullabilityFlags == null || nullabilityFlags.canBeNull()) { return types; } @@ -78,21 +80,30 @@ public class DataFlowInfo { return enrichedTypes; } + @NotNull + public List getPossibleTypesForVariable(VariableDescriptor variableDescriptor) { + return getPossibleTypes(variableDescriptor); + } + + public List getPossibleTypesForReceiver(@NotNull ReceiverDescriptor receiver) { + return getPossibleTypes(receiver); + } + public DataFlowInfo equalsToNull(@NotNull VariableDescriptor variableDescriptor, boolean notNull) { return new DataFlowInfo(getEqualsToNullMap(variableDescriptor, notNull), typeInfo); } - private ImmutableMap getEqualsToNullMap(VariableDescriptor variableDescriptor, boolean notNull) { - Map builder = Maps.newHashMap(nullabilityInfo); + private ImmutableMap getEqualsToNullMap(VariableDescriptor variableDescriptor, boolean notNull) { + Map builder = Maps.newHashMap(nullabilityInfo); NullabilityFlags nullabilityFlags = nullabilityInfo.get(variableDescriptor); boolean varNotNull = notNull || (nullabilityFlags != null && !nullabilityFlags.canBeNull); builder.put(variableDescriptor, new NullabilityFlags(!varNotNull, varNotNull)); return ImmutableMap.copyOf(builder); } - private ImmutableMap getEqualsToNullMap(VariableDescriptor[] variableDescriptors, boolean notNull) { + private ImmutableMap getEqualsToNullMap(VariableDescriptor[] variableDescriptors, boolean notNull) { if (variableDescriptors.length == 0) return nullabilityInfo; - Map builder = Maps.newHashMap(nullabilityInfo); + Map builder = Maps.newHashMap(nullabilityInfo); for (VariableDescriptor variableDescriptor : variableDescriptors) { if (variableDescriptor != null) { NullabilityFlags nullabilityFlags = nullabilityInfo.get(variableDescriptor); @@ -104,14 +115,14 @@ public class DataFlowInfo { } public DataFlowInfo isInstanceOf(@NotNull VariableDescriptor variableDescriptor, @NotNull JetType type) { - ListMultimap newTypeInfo = copyTypeInfo(); + ListMultimap newTypeInfo = copyTypeInfo(); newTypeInfo.put(variableDescriptor, type); return new DataFlowInfo(getEqualsToNullMap(variableDescriptor, !type.isNullable()), newTypeInfo); } public DataFlowInfo isInstanceOf(@NotNull VariableDescriptor[] variableDescriptors, @NotNull JetType type) { if (variableDescriptors.length == 0) return this; - ListMultimap newTypeInfo = copyTypeInfo(); + ListMultimap newTypeInfo = copyTypeInfo(); for (VariableDescriptor variableDescriptor : variableDescriptors) { if (variableDescriptor != null) { newTypeInfo.put(variableDescriptor, type); @@ -121,55 +132,55 @@ public class DataFlowInfo { } public DataFlowInfo and(DataFlowInfo other) { - Map nullabilityMapBuilder = Maps.newHashMap(); + Map nullabilityMapBuilder = Maps.newHashMap(); nullabilityMapBuilder.putAll(nullabilityInfo); - for (Map.Entry entry : other.nullabilityInfo.entrySet()) { - VariableDescriptor variableDescriptor = entry.getKey(); + for (Map.Entry entry : other.nullabilityInfo.entrySet()) { + Object key = entry.getKey(); NullabilityFlags otherFlags = entry.getValue(); - NullabilityFlags thisFlags = nullabilityInfo.get(variableDescriptor); + NullabilityFlags thisFlags = nullabilityInfo.get(key); if (thisFlags != null) { - nullabilityMapBuilder.put(variableDescriptor, thisFlags.and(otherFlags)); + nullabilityMapBuilder.put(key, thisFlags.and(otherFlags)); } else { - nullabilityMapBuilder.put(variableDescriptor, otherFlags); + nullabilityMapBuilder.put(key, otherFlags); } } - ListMultimap newTypeInfo = copyTypeInfo(); + ListMultimap newTypeInfo = copyTypeInfo(); newTypeInfo.putAll(other.typeInfo); return new DataFlowInfo(ImmutableMap.copyOf(nullabilityMapBuilder), newTypeInfo); } - private ListMultimap copyTypeInfo() { - ListMultimap newTypeInfo = Multimaps.newListMultimap(Maps.>newHashMap(), CommonSuppliers.getArrayListSupplier()); + private ListMultimap copyTypeInfo() { + ListMultimap newTypeInfo = Multimaps.newListMultimap(Maps.>newHashMap(), CommonSuppliers.getArrayListSupplier()); newTypeInfo.putAll(typeInfo); return newTypeInfo; } public DataFlowInfo or(DataFlowInfo other) { - Map builder = Maps.newHashMap(nullabilityInfo); + Map builder = Maps.newHashMap(nullabilityInfo); builder.keySet().retainAll(other.nullabilityInfo.keySet()); - for (Map.Entry entry : builder.entrySet()) { - VariableDescriptor variableDescriptor = entry.getKey(); + for (Map.Entry entry : builder.entrySet()) { + Object key = entry.getKey(); NullabilityFlags thisFlags = entry.getValue(); - NullabilityFlags otherFlags = other.nullabilityInfo.get(variableDescriptor); + NullabilityFlags otherFlags = other.nullabilityInfo.get(key); assert (otherFlags != null); - builder.put(variableDescriptor, thisFlags.or(otherFlags)); + builder.put(key, thisFlags.or(otherFlags)); } - ListMultimap newTypeInfo = Multimaps.newListMultimap(Maps.>newHashMap(), CommonSuppliers.getArrayListSupplier()); + ListMultimap newTypeInfo = Multimaps.newListMultimap(Maps.>newHashMap(), CommonSuppliers.getArrayListSupplier()); - Set keys = newTypeInfo.keySet(); + Set keys = newTypeInfo.keySet(); keys.retainAll(other.typeInfo.keySet()); - for (VariableDescriptor variableDescriptor : keys) { - Collection thisTypes = typeInfo.get(variableDescriptor); - Collection otherTypes = other.typeInfo.get(variableDescriptor); + for (Object key : keys) { + Collection thisTypes = typeInfo.get(key); + Collection otherTypes = other.typeInfo.get(key); Collection newTypes = Sets.newHashSet(thisTypes); newTypes.retainAll(otherTypes); - newTypeInfo.putAll(variableDescriptor, newTypes); + newTypeInfo.putAll(key, newTypes); } return new DataFlowInfo(ImmutableMap.copyOf(builder), newTypeInfo); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index bc1770da090..0f31a0bc99d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -20,7 +20,7 @@ import org.jetbrains.jet.lang.diagnostics.DiagnosticWithPsiElement; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.calls.CallResolver; -import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResult; +import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults; import org.jetbrains.jet.lang.resolve.constants.*; import org.jetbrains.jet.lang.resolve.constants.StringValue; import org.jetbrains.jet.lang.resolve.scopes.JetScope; @@ -161,7 +161,6 @@ public class JetTypeInferrer { private final JetSemanticServices semanticServices; private final JetFlowInformationProvider flowInformationProvider; - private final CallResolver callResolver; private final Map patternsToDataFlowInfo = Maps.newHashMap(); private final Map> patternsToBoundVariableLists = Maps.newHashMap(); @@ -169,29 +168,26 @@ public class JetTypeInferrer { public JetTypeInferrer(@NotNull JetFlowInformationProvider flowInformationProvider, @NotNull JetSemanticServices semanticServices) { this.semanticServices = semanticServices; this.flowInformationProvider = flowInformationProvider; - this.callResolver = new CallResolver(semanticServices, this); } public Services getServices(@NotNull BindingTrace trace) { return new Services(trace); } - public CallResolver getCallResolver() { - return callResolver; - } - public class Services { private final BindingTrace trace; private final CompileTimeConstantResolver compileTimeConstantResolver; private final TypeInferrerVisitor typeInferrerVisitor; private final TypeInferrerVisitorWithNamespaces typeInferrerVisitorWithNamespaces; + private final CallResolver callResolver; private Services(BindingTrace trace) { this.trace = trace; this.compileTimeConstantResolver = new CompileTimeConstantResolver(semanticServices, trace); this.typeInferrerVisitor = new TypeInferrerVisitor(); this.typeInferrerVisitorWithNamespaces = new TypeInferrerVisitorWithNamespaces(); + this.callResolver = new CallResolver(semanticServices, JetTypeInferrer.this, DataFlowInfo.getEmpty()); } public TypeInferrerVisitorWithWritableScope newTypeInferrerVisitorWithWritableScope(WritableScope scope) { @@ -516,7 +512,7 @@ public class JetTypeInferrer { VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(expression, context); boolean appropriateTypeFound = false; if (variableDescriptor != null) { - List possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypes(variableDescriptor)); + List possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)); Collections.reverse(possibleTypes); for (JetType possibleType : possibleTypes) { if (semanticServices.getTypeChecker().isSubtypeOf(possibleType, context.expectedType)) { @@ -612,6 +608,9 @@ public class JetTypeInferrer { public final JetType expectedType; public final JetType expectedReturnType; + @Deprecated // Use a getter + private CallResolver callResolver; + @Deprecated // Only factory methods private TypeInferenceContext( @NotNull BindingTrace trace, @@ -666,6 +665,34 @@ public class JetTypeInferrer { if (expectedType == newExpectedType && expectedReturnType == newExpectedReturnType) return this; return newContext(trace, scope, dataFlowInfo, newExpectedType, newExpectedReturnType); } + + public CallResolver getCallResolver() { + if (callResolver == null) { + callResolver = new CallResolver(semanticServices, JetTypeInferrer.this, this.dataFlowInfo); + } + return callResolver; + } + + @Nullable + public FunctionDescriptor resolveCallWithGivenName(@NotNull Call call, @NotNull JetReferenceExpression functionReference, @NotNull String name, @NotNull ReceiverDescriptor receiver) { + return getCallResolver().resolveCallWithGivenName(trace, scope, call, functionReference, name, receiver, expectedType); + } + + @Nullable + public JetType resolveCall(@NotNull ReceiverDescriptor receiver, @NotNull JetCallElement call) { + return getCallResolver().resolveCall(trace, scope, receiver, call, expectedType); + } + + @Nullable + public VariableDescriptor resolveSimpleProperty(@NotNull ReceiverDescriptor receiver, @NotNull JetSimpleNameExpression nameExpression) { + return getCallResolver().resolveSimpleProperty(trace, scope, receiver, nameExpression, expectedType); + } + + @NotNull + public OverloadResolutionResults resolveExactSignature(@NotNull ReceiverDescriptor receiver, @NotNull String name, @NotNull List parameterTypes) { + return getCallResolver().resolveExactSignature(scope, receiver, name, parameterTypes); + } + } private class TypeInferrerVisitor extends JetVisitor { @@ -1899,9 +1926,9 @@ public class JetTypeInferrer { @Nullable private JetType checkIterableConvention(@NotNull ExpressionReceiver loopRange, TypeInferenceContext context) { JetExpression loopRangeExpression = loopRange.getExpression(); - OverloadResolutionResult iteratorResolutionResult = callResolver.resolveExactSignature(context.scope, loopRange, "iterator", Collections.emptyList()); - if (iteratorResolutionResult.isSuccess()) { - FunctionDescriptor iteratorFunction = iteratorResolutionResult.getDescriptor(); + OverloadResolutionResults iteratorResolutionResults = context.resolveExactSignature(loopRange, "iterator", Collections.emptyList()); + if (iteratorResolutionResults.isSuccess()) { + FunctionDescriptor iteratorFunction = iteratorResolutionResults.getResult().getResultingDescriptor(); context.trace.record(LOOP_RANGE_ITERATOR, loopRangeExpression, iteratorFunction); @@ -1923,27 +1950,27 @@ public class JetTypeInferrer { context.trace.record(LOOP_RANGE_HAS_NEXT, loopRange.getExpression(), hasNextFunctionSupported ? hasNextFunction : hasNextProperty); } - OverloadResolutionResult nextResolutionResult = callResolver.resolveExactSignature(context.scope, new TransientReceiver(iteratorType), "next", Collections.emptyList()); - if (nextResolutionResult.isAmbiguity()) { + OverloadResolutionResults nextResolutionResults = context.resolveExactSignature(new TransientReceiver(iteratorType), "next", Collections.emptyList()); + if (nextResolutionResults.isAmbiguity()) { // context.trace.getErrorHandler().genericError(reportErrorsOn, "Method 'iterator().next()' is ambiguous for this expression"); context.trace.report(NEXT_AMBIGUITY.on(loopRangeExpression)); - } else if (nextResolutionResult.isNothing()) { + } else if (nextResolutionResults.isNothing()) { // context.trace.getErrorHandler().genericError(reportErrorsOn, "Loop range must have an 'iterator().next()' method"); context.trace.report(NEXT_MISSING.on(loopRangeExpression)); } else { - FunctionDescriptor nextFunction = nextResolutionResult.getDescriptor(); + FunctionDescriptor nextFunction = nextResolutionResults.getResult().getResultingDescriptor(); context.trace.record(LOOP_RANGE_NEXT, loopRange.getExpression(), nextFunction); return nextFunction.getReturnType(); } } else { - if (iteratorResolutionResult.isAmbiguity()) { + if (iteratorResolutionResults.isAmbiguity()) { // StringBuffer stringBuffer = new StringBuffer("Method 'iterator()' is ambiguous for this expression: "); -// for (FunctionDescriptor functionDescriptor : iteratorResolutionResult.getDescriptors()) { +// for (FunctionDescriptor functionDescriptor : iteratorResolutionResults.getResults()) { // stringBuffer.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append(" "); // } // errorMessage = stringBuffer.toString(); - context.trace.report(ITERATOR_AMBIGUITY.on(loopRangeExpression, iteratorResolutionResult.getDescriptors())); + context.trace.report(ITERATOR_AMBIGUITY.on(loopRangeExpression, iteratorResolutionResults.getResults())); } else { // context.trace.getErrorHandler().genericError(reportErrorsOn, errorMessage); @@ -1955,21 +1982,21 @@ public class JetTypeInferrer { @Nullable private FunctionDescriptor checkHasNextFunctionSupport(@NotNull JetExpression loopRange, @NotNull JetType iteratorType, TypeInferenceContext context) { - OverloadResolutionResult hasNextResolutionResult = callResolver.resolveExactSignature(context.scope, new TransientReceiver(iteratorType), "hasNext", Collections.emptyList()); - if (hasNextResolutionResult.isAmbiguity()) { + OverloadResolutionResults hasNextResolutionResults = context.resolveExactSignature(new TransientReceiver(iteratorType), "hasNext", Collections.emptyList()); + if (hasNextResolutionResults.isAmbiguity()) { // context.trace.getErrorHandler().genericError(loopRange.getNode(), "Method 'iterator().hasNext()' is ambiguous for this expression"); context.trace.report(HAS_NEXT_FUNCTION_AMBIGUITY.on(loopRange)); - } else if (hasNextResolutionResult.isNothing()) { + } else if (hasNextResolutionResults.isNothing()) { return null; } else { - assert hasNextResolutionResult.isSuccess(); - JetType hasNextReturnType = hasNextResolutionResult.getDescriptor().getReturnType(); + assert hasNextResolutionResults.isSuccess(); + JetType hasNextReturnType = hasNextResolutionResults.getResult().getResultingDescriptor().getReturnType(); if (!isBoolean(hasNextReturnType)) { // context.trace.getErrorHandler().genericError(loopRange.getNode(), "The 'iterator().hasNext()' method of the loop range must return Boolean, but returns " + hasNextReturnType); context.trace.report(HAS_NEXT_FUNCTION_TYPE_MISMATCH.on(loopRange, hasNextReturnType)); } } - return hasNextResolutionResult.getDescriptor(); + return hasNextResolutionResults.getResult().getResultingDescriptor(); } @Nullable @@ -2032,7 +2059,7 @@ public class JetTypeInferrer { VariableDescriptor variableDescriptor = cleanResolutionContext.services.getVariableDescriptorFromSimpleName(receiverExpression, context); boolean somethingFound = false; if (variableDescriptor != null) { - List possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypes(variableDescriptor)); + List possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)); Collections.reverse(possibleTypes); TemporaryBindingTrace autocastResolutionTrace = TemporaryBindingTrace.create(context.trace); @@ -2163,13 +2190,13 @@ public class JetTypeInferrer { @Nullable private JetType getSelectorReturnType(@NotNull ReceiverDescriptor receiver, @NotNull JetExpression selectorExpression, @NotNull TypeInferenceContext context) { if (selectorExpression instanceof JetCallExpression) { - return callResolver.resolveCall(context.trace, context.scope, receiver, (JetCallExpression) selectorExpression, context.expectedType); + return context.resolveCall(receiver, (JetCallExpression) selectorExpression); } else if (selectorExpression instanceof JetSimpleNameExpression) { JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) selectorExpression; TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace); - VariableDescriptor variableDescriptor = callResolver.resolveSimpleProperty(temporaryTrace, context.scope, receiver, nameExpression, context.expectedType); + VariableDescriptor variableDescriptor = context.replaceBindingTrace(temporaryTrace).resolveSimpleProperty(receiver, nameExpression); if (variableDescriptor != null) { temporaryTrace.commit(); return context.services.checkEnrichedType(variableDescriptor.getOutType(), nameExpression, context); @@ -2202,7 +2229,7 @@ public class JetTypeInferrer { @Override public JetType visitCallExpression(JetCallExpression expression, TypeInferenceContext context) { - JetType expressionType = callResolver.resolveCall(context.trace, context.scope, ReceiverDescriptor.NO_RECEIVER, expression, context.expectedType); + JetType expressionType = context.resolveCall(ReceiverDescriptor.NO_RECEIVER, expression); return context.services.checkType(expressionType, expression, context); } @@ -2239,14 +2266,11 @@ public class JetTypeInferrer { ExpressionReceiver receiver = getExpressionReceiver(baseExpression, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceScope(context.scope)); if (receiver == null) return null; - FunctionDescriptor functionDescriptor = callResolver.resolveCallWithGivenName( - context.trace, - context.scope, + FunctionDescriptor functionDescriptor = context.resolveCallWithGivenName( CallMaker.makeCall(expression), expression.getOperationSign(), name, - receiver, - context.expectedType); + receiver); if (functionDescriptor == null) return null; JetType returnType = functionDescriptor.getReturnType(); @@ -2317,24 +2341,24 @@ public class JetTypeInferrer { String name = "equals"; if (right != null) { ExpressionReceiver receiver = safeGetExpressionReceiver(left, context.replaceScope(context.scope)); - OverloadResolutionResult resolutionResult = callResolver.resolveExactSignature( - context.scope, receiver, "equals", + OverloadResolutionResults resolutionResults = context.resolveExactSignature( + receiver, "equals", Collections.singletonList(JetStandardClasses.getNullableAnyType())); - if (resolutionResult.isSuccess()) { - FunctionDescriptor equals = resolutionResult.getDescriptor(); + if (resolutionResults.isSuccess()) { + FunctionDescriptor equals = resolutionResults.getResult().getResultingDescriptor(); context.trace.record(REFERENCE_TARGET, operationSign, equals); if (ensureBooleanResult(operationSign, name, equals.getReturnType(), context)) { ensureNonemptyIntersectionOfOperandTypes(expression, context); } } else { - if (resolutionResult.isAmbiguity()) { + if (resolutionResults.isAmbiguity()) { // StringBuilder stringBuilder = new StringBuilder(); -// for (FunctionDescriptor functionDescriptor : resolutionResult.getDescriptors()) { +// for (FunctionDescriptor functionDescriptor : resolutionResults.getResults()) { // stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append(" "); // } // context.trace.getErrorHandler().genericError(operationSign.getNode(), "Ambiguous function: " + stringBuilder); - context.trace.report(OVERLOAD_RESOLUTION_AMBIGUITY.on(operationSign, resolutionResult.getDescriptors())); + context.trace.report(OVERLOAD_RESOLUTION_AMBIGUITY.on(operationSign, resolutionResults.getResults())); } else { // context.trace.getErrorHandler().genericError(operationSign.getNode(), "No method 'equals(Any?) : Boolean' available"); @@ -2398,12 +2422,10 @@ public class JetTypeInferrer { private void checkInExpression(JetSimpleNameExpression operationSign, JetExpression left, JetExpression right, TypeInferenceContext context) { String name = "contains"; ExpressionReceiver receiver = safeGetExpressionReceiver(right, context.replaceExpectedType(NO_EXPECTED_TYPE)); - FunctionDescriptor functionDescriptor = callResolver.resolveCallWithGivenName( - context.trace, - context.scope, + FunctionDescriptor functionDescriptor = context.resolveCallWithGivenName( CallMaker.makeCall(operationSign, Collections.singletonList(left)), operationSign, - name, receiver, context.expectedType); + name, receiver); JetType containsType = functionDescriptor != null ? functionDescriptor.getReturnType() : null; ensureBooleanResult(operationSign, name, containsType, context); } @@ -2469,14 +2491,11 @@ public class JetTypeInferrer { ExpressionReceiver receiver = getExpressionReceiver(arrayExpression, context.replaceScope(context.scope)); if (receiver != null) { - FunctionDescriptor functionDescriptor = callResolver.resolveCallWithGivenName( - context.trace, - context.scope, + FunctionDescriptor functionDescriptor = context.resolveCallWithGivenName( CallMaker.makeCall(expression, expression.getIndexExpressions()), - expression, + expression, "get", - receiver, - context.expectedType); + receiver); if (functionDescriptor != null) { return context.services.checkType(functionDescriptor.getReturnType(), expression, contextWithExpectedType); } @@ -2487,14 +2506,11 @@ public class JetTypeInferrer { @Nullable protected JetType getTypeForBinaryCall(JetScope scope, String name, TypeInferenceContext context, JetBinaryExpression binaryExpression) { ExpressionReceiver receiver = safeGetExpressionReceiver(binaryExpression.getLeft(), context.replaceScope(scope)); - FunctionDescriptor functionDescriptor = callResolver.resolveCallWithGivenName( - context.trace, - scope, + FunctionDescriptor functionDescriptor = context.replaceScope(scope).resolveCallWithGivenName( CallMaker.makeCall(binaryExpression), binaryExpression.getOperationReference(), name, - receiver, - context.expectedType); + receiver); if (functionDescriptor != null) { if (receiver.getType().isNullable()) { // TODO : better error message for '1 + nullableVar' case @@ -2746,12 +2762,10 @@ public class JetTypeInferrer { // call, // arrayAccessExpression, // "set", arrayAccessExpression.getArrayExpression(), NO_EXPECTED_TYPE); - FunctionDescriptor functionDescriptor = callResolver.resolveCallWithGivenName( - context.trace, - scope, + FunctionDescriptor functionDescriptor = context.replaceScope(scope).replaceExpectedType(NO_EXPECTED_TYPE).resolveCallWithGivenName( call, arrayAccessExpression, - "set", receiver, NO_EXPECTED_TYPE); + "set", receiver); if (functionDescriptor == null) return null; context.trace.record(REFERENCE_TARGET, operationSign, functionDescriptor); return context.services.checkType(functionDescriptor.getReturnType(), arrayAccessExpression, context); diff --git a/idea/src/org/jetbrains/jet/plugin/annotations/DebugInfoAnnotator.java b/idea/src/org/jetbrains/jet/plugin/annotations/DebugInfoAnnotator.java index 3b82898afe8..f0d8b73d0c8 100644 --- a/idea/src/org/jetbrains/jet/plugin/annotations/DebugInfoAnnotator.java +++ b/idea/src/org/jetbrains/jet/plugin/annotations/DebugInfoAnnotator.java @@ -15,6 +15,7 @@ import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.diagnostics.UnresolvedReferenceDiagnostic; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.types.ErrorUtils; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.plugin.AnalyzerFacade; @@ -91,7 +92,7 @@ public class DebugInfoAnnotator implements Annotator { target = labelTarget.getText(); } else { - Collection declarationDescriptors = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, expression); + Collection> declarationDescriptors = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, expression); if (declarationDescriptors != null) { target = "[" + declarationDescriptors.size() + " descriptors]"; } diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java index a771388c338..9916a18468f 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java @@ -11,6 +11,7 @@ import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetReferenceExpression; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.plugin.AnalyzerFacade; import java.util.Collection; @@ -80,7 +81,7 @@ public abstract class JetPsiReference implements PsiPolyVariantReference { if (psiElement != null) { return psiElement; } - Collection declarationDescriptors = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, myExpression); + Collection> declarationDescriptors = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, myExpression); if (declarationDescriptors != null) return null; return file; } @@ -88,12 +89,12 @@ public abstract class JetPsiReference implements PsiPolyVariantReference { protected ResolveResult[] doMultiResolve() { JetFile file = (JetFile) getElement().getContainingFile(); BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file); - Collection declarationDescriptors = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, myExpression); - if (declarationDescriptors == null) return ResolveResult.EMPTY_ARRAY; - ResolveResult[] results = new ResolveResult[declarationDescriptors.size()]; + Collection> resolvedCalls = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, myExpression); + if (resolvedCalls == null) return ResolveResult.EMPTY_ARRAY; + ResolveResult[] results = new ResolveResult[resolvedCalls.size()]; int i = 0; - for (DeclarationDescriptor descriptor : declarationDescriptors) { - PsiElement element = bindingContext.get(DESCRIPTOR_TO_DECLARATION, descriptor); + for (ResolvedCall resolvedCall : resolvedCalls) { + PsiElement element = bindingContext.get(DESCRIPTOR_TO_DECLARATION, resolvedCall.getResultingDescriptor()); if (element != null) { results[i] = new PsiElementResolveResult(element, true); i++; diff --git a/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java b/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java index 309b9e984bd..058b742d5e6 100644 --- a/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java +++ b/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java @@ -15,7 +15,8 @@ import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.resolve.BindingTraceContext; -import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResult; +import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.parsing.JetParsingTest; @@ -107,14 +108,14 @@ public class JetResolveTest extends ExtensibleResolveTestCase { List parameterTypeList = Arrays.asList(parameterType); JetTypeInferrer.Services typeInferrerServices = JetSemanticServices.createSemanticServices(getProject()).getTypeInferrerServices(new BindingTraceContext(), JetFlowInformationProvider.NONE); - OverloadResolutionResult functions = typeInferrerServices.getCallResolver().resolveExactSignature( + OverloadResolutionResults functions = typeInferrerServices.getCallResolver().resolveExactSignature( classDescriptor.getMemberScope(typeArguments), ReceiverDescriptor.NO_RECEIVER, name, parameterTypeList); - for (FunctionDescriptor function : functions.getDescriptors()) { - List unsubstitutedValueParameters = function.getValueParameters(); + for (ResolvedCall resolvedCall : functions.getResults()) { + List unsubstitutedValueParameters = resolvedCall.getResultingDescriptor().getValueParameters(); for (int i = 0, unsubstitutedValueParametersSize = unsubstitutedValueParameters.size(); i < unsubstitutedValueParametersSize; i++) { ValueParameterDescriptor unsubstitutedValueParameter = unsubstitutedValueParameters.get(i); if (unsubstitutedValueParameter.getOutType().equals(parameterType[i])) { - return function; + return resolvedCall.getResultingDescriptor(); } } }