From 9524b486761a2b3dbcf05a8d6351a08bc1a5dbf9 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Wed, 14 Mar 2012 23:08:59 +0400 Subject: [PATCH] Resolution task is itself a context --- .../jet/lang/resolve/calls/CallResolver.java | 230 +++--------------- .../lang/resolve/calls/ResolutionTask.java | 190 +++++++++++++-- .../lang/resolve/calls/TaskPrioritizer.java | 39 +-- 3 files changed, 226 insertions(+), 233 deletions(-) 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 6a5d73c7c75..19e79507bbf 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 @@ -35,16 +35,15 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices; -import org.jetbrains.jet.lang.types.expressions.OperatorConventions; import org.jetbrains.jet.lang.types.lang.JetStandardClasses; -import org.jetbrains.jet.lexer.JetToken; import org.jetbrains.jet.lexer.JetTokens; import javax.inject.Inject; import java.util.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*; -import static org.jetbrains.jet.lang.resolve.BindingContext.*; +import static org.jetbrains.jet.lang.resolve.BindingContext.AUTOCAST; +import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLUTION_SCOPE; import static org.jetbrains.jet.lang.resolve.calls.ResolutionStatus.*; import static org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl.MAP_TO_CANDIDATE; import static org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl.MAP_TO_RESULT; @@ -109,8 +108,8 @@ public class CallResolver { else { task_prioritizer = TaskPrioritizers.VARIABLE_TASK_PRIORITIZER; } - List> prioritizedTasks = task_prioritizer.computePrioritizedTasks(context.scope, context.call, referencedName, context.trace.getBindingContext(), context.dataFlowInfo); - return resolveCallToDescriptor(context, prioritizedTasks, nameExpression); + List> prioritizedTasks = task_prioritizer.computePrioritizedTasks(context, referencedName, nameExpression); + return doResolveCall(context, prioritizedTasks, nameExpression); } @NotNull @@ -119,7 +118,7 @@ public class CallResolver { @NotNull final JetReferenceExpression functionReference, @NotNull String name) { List> tasks = TaskPrioritizers.FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks( - context.scope, context.call, name, context.trace.getBindingContext(), context.dataFlowInfo); + context, name, functionReference); return doResolveCall(context, tasks, functionReference); } @@ -141,7 +140,7 @@ public class CallResolver { String name = expression.getReferencedName(); if (name == null) return checkArgumentTypesAndFail(context); - prioritizedTasks = TaskPrioritizers.FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(context.scope, context.call, name, context.trace.getBindingContext(), context.dataFlowInfo); + prioritizedTasks = TaskPrioritizers.FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(context, name, functionReference); ResolutionTask.DescriptorCheckStrategy abstractConstructorCheck = new ResolutionTask.DescriptorCheckStrategy() { @Override public boolean performAdvancedChecks(D descriptor, BindingTrace trace, TracingStrategy tracing) { @@ -183,7 +182,8 @@ public class CallResolver { context.trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn)); return checkArgumentTypesAndFail(context); } - prioritizedTasks.add(new ResolutionTask(TaskPrioritizer.convertWithImpliedThis(context.scope, Collections.singletonList(NO_RECEIVER), constructors), context.call, DataFlowInfo.EMPTY)); + Collection> candidates = TaskPrioritizer.convertWithImpliedThis(context.scope, Collections.singletonList(NO_RECEIVER), constructors); + prioritizedTasks.add(new ResolutionTask(candidates, functionReference, context)); // !! DataFlowInfo.EMPTY } else { context.trace.report(NOT_A_CLASS.on(calleeExpression)); @@ -204,7 +204,8 @@ public class CallResolver { context.trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn)); return checkArgumentTypesAndFail(context); } - prioritizedTasks = Collections.singletonList(new ResolutionTask(ResolvedCallImpl.convertCollection(constructors), context.call, DataFlowInfo.EMPTY)); + List> candidates = ResolvedCallImpl.convertCollection(constructors); + prioritizedTasks = Collections.singletonList(new ResolutionTask(candidates, functionReference, context)); // !! DataFlowInfo.EMPTY } else if (calleeExpression != null) { // Here we handle the case where the callee expression must be something of type function, e.g. (foo.bar())(1, 2) @@ -222,13 +223,13 @@ public class CallResolver { FunctionDescriptorUtil.initializeFromFunctionType(functionDescriptor, calleeType, NO_RECEIVER); ResolvedCallImpl resolvedCall = ResolvedCallImpl.create(functionDescriptor); resolvedCall.setReceiverArgument(context.call.getExplicitReceiver()); - prioritizedTasks = Collections.singletonList(new ResolutionTask( - Collections.singleton(resolvedCall), context.call, context.dataFlowInfo)); // strictly speaking, this is a hack: // we need to pass a reference, but there's no reference in the PSI, // so we wrap what we have into a fake reference and pass it on (unwrap on the other end) functionReference = new JetFakeReference(calleeExpression); + + prioritizedTasks = Collections.singletonList(new ResolutionTask(Collections.singleton(resolvedCall), functionReference, context)); } else { // checkTypesWithNoCallee(trace, scope, call); @@ -236,7 +237,7 @@ public class CallResolver { } } - return resolveCallToDescriptor(context, prioritizedTasks, functionReference); + return doResolveCall(context, prioritizedTasks, functionReference); } private OverloadResolutionResults checkArgumentTypesAndFail(BasicResolutionContext context) { @@ -244,14 +245,6 @@ public class CallResolver { return OverloadResolutionResultsImpl.nameNotFound(); } - @NotNull - private OverloadResolutionResults resolveCallToDescriptor( - @NotNull BasicResolutionContext context, - @NotNull final List> prioritizedTasks, // high to low priority - @NotNull final JetReferenceExpression reference) { - return doResolveCall(context, prioritizedTasks, reference); - } - @NotNull private OverloadResolutionResults doResolveCall( @NotNull final BasicResolutionContext context, @@ -264,148 +257,11 @@ public class CallResolver { debugInfo.set(ResolutionDebugInfo.TASKS, prioritizedTasks); - TracingStrategy tracing = new TracingStrategy() { - @Override - public void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCallImpl resolvedCall) { - D descriptor = resolvedCall.getCandidateDescriptor(); -// if (descriptor instanceof VariableAsFunctionDescriptor) { -// VariableAsFunctionDescriptor variableAsFunctionDescriptor = (VariableAsFunctionDescriptor) descriptor; -// trace.record(REFERENCE_TARGET, reference, variableAsFunctionDescriptor.getVariableDescriptor()); -// } -// else { -// } - trace.record(RESOLVED_CALL, context.call.getCalleeExpression(), resolvedCall); - trace.record(REFERENCE_TARGET, reference, descriptor); - } - - @Override - public void recordAmbiguity(BindingTrace trace, Collection> candidates) { - Collection descriptors = Sets.newHashSet(); - for (ResolvedCallImpl candidate : candidates) { - descriptors.add(candidate.getCandidateDescriptor()); - } - trace.record(AMBIGUOUS_REFERENCE_TARGET, reference, descriptors); - } - - @Override - public void unresolvedReference(@NotNull BindingTrace trace) { - trace.report(UNRESOLVED_REFERENCE.on(reference)); - } - - @Override - public void noValueForParameter(@NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter) { - PsiElement reportOn; - JetValueArgumentList valueArgumentList = context.call.getValueArgumentList(); - if (valueArgumentList != null) { - reportOn = valueArgumentList; - } - else { - reportOn = reference; - } - trace.report(NO_VALUE_FOR_PARAMETER.on(reportOn, valueParameter)); - } - - @Override - public void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor expectedReceiver) { - trace.report(MISSING_RECEIVER.on(reference, expectedReceiver.getType())); - } - - @Override - public void wrongReceiverType(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor receiverParameter, @NotNull ReceiverDescriptor receiverArgument) { - if (receiverArgument instanceof ExpressionReceiver) { - ExpressionReceiver expressionReceiver = (ExpressionReceiver) receiverArgument; - trace.report(TYPE_MISMATCH.on(expressionReceiver.getExpression(), receiverParameter.getType(), receiverArgument.getType())); - } - else { - trace.report(TYPE_MISMATCH.on(reference, receiverParameter.getType(), receiverArgument.getType())); - } - } - - @Override - public void noReceiverAllowed(@NotNull BindingTrace trace) { - trace.report(NO_RECEIVER_ADMITTED.on(reference)); - } - - @Override - public void wrongNumberOfTypeArguments(@NotNull BindingTrace trace, int expectedTypeArgumentCount) { - JetTypeArgumentList typeArgumentList = context.call.getTypeArgumentList(); - if (typeArgumentList != null) { - trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(typeArgumentList, expectedTypeArgumentCount)); - } - else { - trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(reference, expectedTypeArgumentCount)); - } - } - - @Override - public void ambiguity(@NotNull BindingTrace trace, @NotNull Collection> descriptors) { - trace.report(OVERLOAD_RESOLUTION_AMBIGUITY.on(context.call.getCallElement(), descriptors)); - } - - @Override - public void noneApplicable(@NotNull BindingTrace trace, @NotNull Collection> descriptors) { - trace.report(NONE_APPLICABLE.on(reference, descriptors)); - } - - @Override - public void instantiationOfAbstractClass(@NotNull BindingTrace trace) { - trace.report(CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS.on(context.call.getCallElement())); - } - - @Override - public void typeInferenceFailed(@NotNull BindingTrace trace, SolutionStatus status) { - assert !status.isSuccessful(); - trace.report(TYPE_INFERENCE_FAILED.on(context.call.getCallElement(), status)); - } - - @Override - public void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type) { - ASTNode callOperationNode = context.call.getCallOperationNode(); - if (callOperationNode != null) { - trace.report(UNSAFE_CALL.on(callOperationNode.getPsi(), type)); - } - else { - PsiElement callElement = context.call.getCallElement(); - if (callElement instanceof JetBinaryExpression) { - JetBinaryExpression binaryExpression = (JetBinaryExpression) callElement; - JetSimpleNameExpression operationReference = binaryExpression.getOperationReference(); - - String operationString = operationReference.getReferencedNameElementType() == JetTokens.IDENTIFIER ? - operationReference.getText() : - OperatorConventions.getNameForOperationSymbol((JetToken) operationReference.getReferencedNameElementType()); - - JetExpression right = binaryExpression.getRight(); - if (right != null) { - trace.report(UNSAFE_INFIX_CALL.on(reference, binaryExpression.getLeft().getText(), operationString, right.getText())); - } - } - else { - trace.report(UNSAFE_CALL.on(reference, type)); - } - } - } - - @Override - public void unnecessarySafeCall(@NotNull BindingTrace trace, @NotNull JetType type) { - ASTNode callOperationNode = context.call.getCallOperationNode(); - assert callOperationNode != null; - trace.report(UNNECESSARY_SAFE_CALL.on(callOperationNode.getPsi(), type)); - } - - @Override - public void danglingFunctionLiteralArgumentSuspected(@NotNull BindingTrace trace, @NotNull List functionLiteralArguments) { - for (JetExpression functionLiteralArgument : functionLiteralArguments) { - trace.report(DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED.on(functionLiteralArgument)); - } - } - }; - TemporaryBindingTrace traceForFirstNonemptyCandidateSet = null; OverloadResolutionResultsImpl resultsForFirstNonemptyCandidateSet = null; for (ResolutionTask task : prioritizedTasks) { TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace); - BasicResolutionContext newContext = BasicResolutionContext.create(temporaryTrace, context.scope, task.getCall(), context.expectedType, context.dataFlowInfo); - OverloadResolutionResultsImpl results = performResolutionGuardedForExtraFunctionLiteralArguments(new TaskResolutionContext(task, tracing, newContext)); + OverloadResolutionResultsImpl results = performResolutionGuardedForExtraFunctionLiteralArguments(task.withTrace(temporaryTrace)); if (results.isSuccess()) { temporaryTrace.commit(); @@ -435,8 +291,8 @@ public class CallResolver { ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @NotNull - private OverloadResolutionResultsImpl performResolutionGuardedForExtraFunctionLiteralArguments(TaskResolutionContext context) { - OverloadResolutionResultsImpl results = performResolution(context); + private OverloadResolutionResultsImpl performResolutionGuardedForExtraFunctionLiteralArguments(ResolutionTask task) { + OverloadResolutionResultsImpl results = performResolution(task); // If resolution fails, we should check for some of the following situations: // class A { @@ -455,27 +311,24 @@ public class CallResolver { // } EnumSet someFailed = EnumSet.of(OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES, OverloadResolutionResults.Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH); - if (someFailed.contains(results.getResultCode()) && !context.call.getFunctionLiteralArguments().isEmpty()) { + if (someFailed.contains(results.getResultCode()) && !task.call.getFunctionLiteralArguments().isEmpty()) { // We have some candidates that failed for some reason // And we have a suspect: the function literal argument // Now, we try to remove this argument and see if it helps Collection> newCandidates = Lists.newArrayList(); - for (ResolvedCallImpl candidate : context.task.getCandidates()) { + for (ResolvedCallImpl candidate : task.getCandidates()) { newCandidates.add(ResolvedCallImpl.create(candidate.getCandidateDescriptor())); } - ResolutionTask newTask = new ResolutionTask(newCandidates, new DelegatingCall(context.call) { - @NotNull - @Override - public List getFunctionLiteralArguments() { - return Collections.emptyList(); - } - }, context.dataFlowInfo); - - BasicResolutionContext newBasicContext = BasicResolutionContext.create(TemporaryBindingTrace.create(context.trace), context.scope, context.call, context.expectedType, context.dataFlowInfo); - TaskResolutionContext newContext = new TaskResolutionContext(newTask, context.tracing, newBasicContext); + ResolutionTask newContext = new ResolutionTask(newCandidates, task.reference, TemporaryBindingTrace.create(task.trace), task.scope, new DelegatingCall(task.call) { + @NotNull + @Override + public List getFunctionLiteralArguments() { + return Collections.emptyList(); + } + }, task.expectedType, task.dataFlowInfo); OverloadResolutionResultsImpl resultsWithFunctionLiteralsStripped = performResolution(newContext); if (resultsWithFunctionLiteralsStripped.isSuccess() || resultsWithFunctionLiteralsStripped.isAmbiguity()) { - context.tracing.danglingFunctionLiteralArgumentSuspected(context.trace, context.call.getFunctionLiteralArguments()); + task.tracing.danglingFunctionLiteralArgumentSuspected(task.trace, task.call.getFunctionLiteralArguments()); } } @@ -483,13 +336,13 @@ public class CallResolver { } @NotNull - private OverloadResolutionResultsImpl performResolution(TaskResolutionContext taskContext) { - for (ResolvedCallImpl candidateCall : taskContext.task.getCandidates()) { + private OverloadResolutionResultsImpl performResolution(ResolutionTask task) { + for (ResolvedCallImpl candidateCall : task.getCandidates()) { D candidate = candidateCall.getCandidateDescriptor(); - TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(taskContext.trace); + TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(task.trace); candidateCall.setTrace(temporaryTrace); - CallResolutionContext context = new CallResolutionContext(candidateCall, taskContext, temporaryTrace, taskContext.tracing); + CallResolutionContext context = new CallResolutionContext(candidateCall, task, temporaryTrace, task.tracing); context.tracing.bindReference(context.trace, candidateCall); @@ -555,7 +408,7 @@ public class CallResolver { } } - taskContext.task.performAdvancedChecks(candidate, context.trace, context.tracing); + task.performAdvancedChecks(candidate, context.trace, context.tracing); // 'super' cannot be passed as an argument, for receiver arguments expression typer does not track this // See TaskPrioritizer for more @@ -571,7 +424,7 @@ public class CallResolver { Set> successfulCandidates = Sets.newLinkedHashSet(); Set> failedCandidates = Sets.newLinkedHashSet(); - for (ResolvedCallImpl candidateCall : taskContext.task.getCandidates()) { + for (ResolvedCallImpl candidateCall : task.getCandidates()) { ResolutionStatus status = candidateCall.getStatus(); if (status.isSuccess()) { successfulCandidates.add(candidateCall); @@ -582,9 +435,9 @@ public class CallResolver { } } - OverloadResolutionResultsImpl results = computeResultAndReportErrors(taskContext.trace, taskContext.tracing, successfulCandidates, failedCandidates); + OverloadResolutionResultsImpl results = computeResultAndReportErrors(task.trace, task.tracing, successfulCandidates, failedCandidates); if (!results.singleResult()) { - checkTypesWithNoCallee(taskContext.toBasic()); + checkTypesWithNoCallee(task.toBasic()); } return results; } @@ -1033,23 +886,12 @@ public class CallResolver { return true; } - private static class TaskResolutionContext extends ResolutionContext { - /*package*/ final ResolutionTask task; - /*package*/ final TracingStrategy tracing; - - public TaskResolutionContext(ResolutionTask task, TracingStrategy tracing, BasicResolutionContext context) { - super(context.trace, context.scope, task.getCall(), context.expectedType, context.dataFlowInfo); - this.task = task; - this.tracing = tracing; - } - } - private static final class CallResolutionContext extends ResolutionContext { /*package*/ final ResolvedCallImpl candidateCall; /*package*/ final TracingStrategy tracing; - public CallResolutionContext(ResolvedCallImpl candidateCall, TaskResolutionContext taskResolutionContext, BindingTrace trace, TracingStrategy tracing) { - super(trace, taskResolutionContext.scope, taskResolutionContext.task.getCall(), taskResolutionContext.expectedType, taskResolutionContext.dataFlowInfo); + public CallResolutionContext(ResolvedCallImpl candidateCall, ResolutionTask task, BindingTrace trace, TracingStrategy tracing) { + super(trace, task.scope, task.call, task.expectedType, task.dataFlowInfo); this.candidateCall = candidateCall; this.tracing = tracing; } 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 463451b11ad..e79d5d89da5 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 @@ -16,39 +16,52 @@ package org.jetbrains.jet.lang.resolve.calls; +import com.google.common.collect.Sets; +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.CallableDescriptor; -import org.jetbrains.jet.lang.psi.Call; +import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; +import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; +import org.jetbrains.jet.lang.resolve.calls.inference.SolutionStatus; +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.JetType; +import org.jetbrains.jet.lang.types.expressions.OperatorConventions; +import org.jetbrains.jet.lexer.JetToken; +import org.jetbrains.jet.lexer.JetTokens; import java.util.Collection; +import java.util.List; + +import static org.jetbrains.jet.lang.diagnostics.Errors.*; +import static org.jetbrains.jet.lang.diagnostics.Errors.DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED; +import static org.jetbrains.jet.lang.resolve.BindingContext.AMBIGUOUS_REFERENCE_TARGET; +import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; +import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL; /** * Stores candidates for call resolution. * * @author abreslav */ -public class ResolutionTask { - private final Call call; +public class ResolutionTask extends ResolutionContext { private final Collection> candidates; - private final DataFlowInfo dataFlowInfo; + /*package*/ final JetReferenceExpression reference; private DescriptorCheckStrategy checkingStrategy; - - public ResolutionTask( - @NotNull Collection> candidates, - @NotNull Call call, - @NotNull DataFlowInfo dataFlowInfo - ) { + public ResolutionTask(@NotNull Collection> candidates, @NotNull JetReferenceExpression reference, + BindingTrace trace, JetScope scope, Call call, JetType expectedType, DataFlowInfo dataFlowInfo) { + super(trace, scope, call, expectedType, dataFlowInfo); this.candidates = candidates; - this.call = call; - this.dataFlowInfo = dataFlowInfo; + this.reference = reference; } - @NotNull - public DataFlowInfo getDataFlowInfo() { - return dataFlowInfo; + public ResolutionTask(@NotNull Collection> candidates, @NotNull JetReferenceExpression reference, @NotNull BasicResolutionContext context) { + this(candidates, reference, context.trace, context.scope, context.call, context.expectedType, context.dataFlowInfo); } @NotNull @@ -56,11 +69,6 @@ public class ResolutionTask { return candidates; } - @NotNull - public Call getCall() { - return call; - } - public void setCheckingStrategy(DescriptorCheckStrategy strategy) { checkingStrategy = strategy; } @@ -72,7 +80,149 @@ public class ResolutionTask { return true; } + public ResolutionTask withTrace(BindingTrace newTrace) { + ResolutionTask newTask = new ResolutionTask(candidates, reference, newTrace, scope, call, expectedType, dataFlowInfo); + newTask.setCheckingStrategy(checkingStrategy); + return newTask; + } + public interface DescriptorCheckStrategy { boolean performAdvancedChecks(D descriptor, BindingTrace trace, TracingStrategy tracing); } + + public final TracingStrategy tracing = new TracingStrategy() { + @Override + public void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCallImpl resolvedCall) { + D descriptor = resolvedCall.getCandidateDescriptor(); + // if (descriptor instanceof VariableAsFunctionDescriptor) { + // VariableAsFunctionDescriptor variableAsFunctionDescriptor = (VariableAsFunctionDescriptor) descriptor; + // trace.record(REFERENCE_TARGET, reference, variableAsFunctionDescriptor.getVariableDescriptor()); + // } + // else { + // } + trace.record(RESOLVED_CALL, call.getCalleeExpression(), resolvedCall); + trace.record(REFERENCE_TARGET, reference, descriptor); + } + + @Override + public void recordAmbiguity(BindingTrace trace, Collection> candidates) { + Collection descriptors = Sets.newHashSet(); + for (ResolvedCallImpl candidate : candidates) { + descriptors.add(candidate.getCandidateDescriptor()); + } + trace.record(AMBIGUOUS_REFERENCE_TARGET, reference, descriptors); + } + + @Override + public void unresolvedReference(@NotNull BindingTrace trace) { + trace.report(UNRESOLVED_REFERENCE.on(reference)); + } + + @Override + public void noValueForParameter(@NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter) { + PsiElement reportOn; + JetValueArgumentList valueArgumentList = call.getValueArgumentList(); + if (valueArgumentList != null) { + reportOn = valueArgumentList; + } + else { + reportOn = reference; + } + trace.report(NO_VALUE_FOR_PARAMETER.on(reportOn, valueParameter)); + } + + @Override + public void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor expectedReceiver) { + trace.report(MISSING_RECEIVER.on(reference, expectedReceiver.getType())); + } + + @Override + public void wrongReceiverType(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor receiverParameter, @NotNull ReceiverDescriptor receiverArgument) { + if (receiverArgument instanceof ExpressionReceiver) { + ExpressionReceiver expressionReceiver = (ExpressionReceiver) receiverArgument; + trace.report(TYPE_MISMATCH.on(expressionReceiver.getExpression(), receiverParameter.getType(), receiverArgument.getType())); + } + else { + trace.report(TYPE_MISMATCH.on(reference, receiverParameter.getType(), receiverArgument.getType())); + } + } + + @Override + public void noReceiverAllowed(@NotNull BindingTrace trace) { + trace.report(NO_RECEIVER_ADMITTED.on(reference)); + } + + @Override + public void wrongNumberOfTypeArguments(@NotNull BindingTrace trace, int expectedTypeArgumentCount) { + JetTypeArgumentList typeArgumentList = call.getTypeArgumentList(); + if (typeArgumentList != null) { + trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(typeArgumentList, expectedTypeArgumentCount)); + } + else { + trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(reference, expectedTypeArgumentCount)); + } + } + + @Override + public void ambiguity(@NotNull BindingTrace trace, @NotNull Collection> descriptors) { + trace.report(OVERLOAD_RESOLUTION_AMBIGUITY.on(call.getCallElement(), descriptors)); + } + + @Override + public void noneApplicable(@NotNull BindingTrace trace, @NotNull Collection> descriptors) { + trace.report(NONE_APPLICABLE.on(reference, descriptors)); + } + + @Override + public void instantiationOfAbstractClass(@NotNull BindingTrace trace) { + trace.report(CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS.on(call.getCallElement())); + } + + @Override + public void typeInferenceFailed(@NotNull BindingTrace trace, SolutionStatus status) { + assert !status.isSuccessful(); + trace.report(TYPE_INFERENCE_FAILED.on(call.getCallElement(), status)); + } + + @Override + public void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type) { + ASTNode callOperationNode = call.getCallOperationNode(); + if (callOperationNode != null) { + trace.report(UNSAFE_CALL.on(callOperationNode.getPsi(), type)); + } + else { + PsiElement callElement = call.getCallElement(); + if (callElement instanceof JetBinaryExpression) { + JetBinaryExpression binaryExpression = (JetBinaryExpression) callElement; + JetSimpleNameExpression operationReference = binaryExpression.getOperationReference(); + + String operationString = operationReference.getReferencedNameElementType() == JetTokens.IDENTIFIER ? + operationReference.getText() : + OperatorConventions.getNameForOperationSymbol((JetToken) operationReference.getReferencedNameElementType()); + + JetExpression right = binaryExpression.getRight(); + if (right != null) { + trace.report(UNSAFE_INFIX_CALL.on(reference, binaryExpression.getLeft().getText(), operationString, right.getText())); + } + } + else { + trace.report(UNSAFE_CALL.on(reference, type)); + } + } + } + + @Override + public void unnecessarySafeCall(@NotNull BindingTrace trace, @NotNull JetType type) { + ASTNode callOperationNode = call.getCallOperationNode(); + assert callOperationNode != null; + trace.report(UNNECESSARY_SAFE_CALL.on(callOperationNode.getPsi(), type)); + } + + @Override + public void danglingFunctionLiteralArgumentSuspected(@NotNull BindingTrace trace, @NotNull List functionLiteralArguments) { + for (JetExpression functionLiteralArgument : functionLiteralArguments) { + trace.report(DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED.on(functionLiteralArgument)); + } + } + }; } 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 4e4ab49370d..1051f85891c 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 @@ -20,12 +20,10 @@ 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.Call; import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.JetReferenceExpression; import org.jetbrains.jet.lang.psi.JetSuperExpression; -import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.DescriptorUtils; -import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastService; import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.scopes.JetScope; @@ -76,21 +74,24 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor } @NotNull - public List> computePrioritizedTasks(@NotNull JetScope scope, @NotNull Call call, @NotNull String name, - @NotNull BindingContext bindingContext, @NotNull DataFlowInfo dataFlowInfo) { + public List> computePrioritizedTasks(@NotNull BasicResolutionContext context, @NotNull String name, + @NotNull JetReferenceExpression functionReference) { List> result = Lists.newArrayList(); - ReceiverDescriptor explicitReceiver = call.getExplicitReceiver(); + ReceiverDescriptor explicitReceiver = context.call.getExplicitReceiver(); + JetScope scope = context.scope; if (explicitReceiver.exists() && explicitReceiver.getType() instanceof NamespaceType) { + // Receiver is a namespace scope = explicitReceiver.getType().getMemberScope(); explicitReceiver = NO_RECEIVER; } - doComputeTasks(scope, explicitReceiver, call, name, result, new AutoCastServiceImpl(dataFlowInfo, bindingContext)); + doComputeTasks(scope, explicitReceiver, name, result, context, functionReference); return result; } - private void doComputeTasks(JetScope scope, ReceiverDescriptor receiver, Call call, String name, List> result, @NotNull AutoCastService autoCastService) { + private void doComputeTasks(JetScope scope, ReceiverDescriptor receiver, String name, List> result, @NotNull BasicResolutionContext context, @NotNull JetReferenceExpression functionReference) { + AutoCastServiceImpl autoCastService = new AutoCastServiceImpl(context.dataFlowInfo, context.trace.getBindingContext()); DataFlowInfo dataFlowInfo = autoCastService.getDataFlowInfo(); List implicitReceivers = Lists.newArrayList(); scope.getImplicitReceiversHierarchy(implicitReceivers); @@ -113,21 +114,21 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor // If the call is of the form super.foo(), it can actually be only a member // But if there's no appropriate member, we would like to report that super cannot be a receiver for an extension // Thus, put members first - addTask(result, call, members, dataFlowInfo); - addTask(result, call, locals, dataFlowInfo); + addTask(result, members, context, functionReference); + addTask(result, locals, context, functionReference); } else { - addTask(result, call, locals, dataFlowInfo); - addTask(result, call, members, dataFlowInfo); + addTask(result, locals, context, functionReference); + addTask(result, members, context, functionReference); } for (ReceiverDescriptor implicitReceiver : implicitReceivers) { Collection memberExtensions = getExtensionsByName(implicitReceiver.getType().getMemberScope(), name); List variantsForImplicitReceiver = autoCastService.getVariantsForReceiver(implicitReceiver); - addTask(result, call, convertWithReceivers(memberExtensions, variantsForImplicitReceiver, variantsForExplicitReceiver), dataFlowInfo); + addTask(result, convertWithReceivers(memberExtensions, variantsForImplicitReceiver, variantsForExplicitReceiver), context, functionReference); } - addTask(result, call, nonlocals, dataFlowInfo); + addTask(result, nonlocals, context, functionReference); } else { Collection> functions = convertWithImpliedThis(scope, Collections.singletonList(receiver), getNonExtensionsByName(scope, name)); @@ -137,13 +138,13 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor //noinspection unchecked,RedundantTypeArguments TaskPrioritizer.splitLexicallyLocalDescriptors(functions, scope.getContainingDeclaration(), locals, nonlocals); - addTask(result, call, locals, dataFlowInfo); + addTask(result, locals, context, functionReference); for (ReceiverDescriptor implicitReceiver : implicitReceivers) { - doComputeTasks(scope, implicitReceiver, call, name, result, autoCastService); + doComputeTasks(scope, implicitReceiver, name, result, context, functionReference); } - addTask(result, call, nonlocals, dataFlowInfo); + addTask(result, nonlocals, context, functionReference); } } @@ -211,9 +212,9 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor return false; } - private void addTask(@NotNull List> result, @NotNull Call call, @NotNull Collection> candidates, @NotNull DataFlowInfo dataFlowInfo) { + private void addTask(@NotNull List> result, @NotNull Collection> candidates, @NotNull BasicResolutionContext context, @NotNull JetReferenceExpression functionReference) { if (candidates.isEmpty()) return; - result.add(new ResolutionTask(candidates, call, dataFlowInfo)); + result.add(new ResolutionTask(candidates, functionReference, context)); } @NotNull