Resolution task is itself a context

This commit is contained in:
Andrey Breslav
2012-03-14 23:08:59 +04:00
parent 5b7dff2bad
commit 9524b48676
3 changed files with 226 additions and 233 deletions
@@ -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<ResolutionTask<VariableDescriptor>> prioritizedTasks = task_prioritizer.computePrioritizedTasks(context.scope, context.call, referencedName, context.trace.getBindingContext(), context.dataFlowInfo);
return resolveCallToDescriptor(context, prioritizedTasks, nameExpression);
List<ResolutionTask<VariableDescriptor>> 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<ResolutionTask<FunctionDescriptor>> 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 <D extends CallableDescriptor> 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<FunctionDescriptor>(TaskPrioritizer.<FunctionDescriptor>convertWithImpliedThis(context.scope, Collections.<ReceiverDescriptor>singletonList(NO_RECEIVER), constructors), context.call, DataFlowInfo.EMPTY));
Collection<ResolvedCallImpl<FunctionDescriptor>> candidates = TaskPrioritizer.<FunctionDescriptor>convertWithImpliedThis(context.scope, Collections.<ReceiverDescriptor>singletonList(NO_RECEIVER), constructors);
prioritizedTasks.add(new ResolutionTask<FunctionDescriptor>(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<FunctionDescriptor>(ResolvedCallImpl.<FunctionDescriptor>convertCollection(constructors), context.call, DataFlowInfo.EMPTY));
List<ResolvedCallImpl<FunctionDescriptor>> candidates = ResolvedCallImpl.<FunctionDescriptor>convertCollection(constructors);
prioritizedTasks = Collections.singletonList(new ResolutionTask<FunctionDescriptor>(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<FunctionDescriptor> resolvedCall = ResolvedCallImpl.<FunctionDescriptor>create(functionDescriptor);
resolvedCall.setReceiverArgument(context.call.getExplicitReceiver());
prioritizedTasks = Collections.singletonList(new ResolutionTask<FunctionDescriptor>(
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<FunctionDescriptor>(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 <D extends CallableDescriptor> OverloadResolutionResults<D> checkArgumentTypesAndFail(BasicResolutionContext context) {
@@ -244,14 +245,6 @@ public class CallResolver {
return OverloadResolutionResultsImpl.nameNotFound();
}
@NotNull
private <D extends CallableDescriptor> OverloadResolutionResults<D> resolveCallToDescriptor(
@NotNull BasicResolutionContext context,
@NotNull final List<ResolutionTask<D>> prioritizedTasks, // high to low priority
@NotNull final JetReferenceExpression reference) {
return doResolveCall(context, prioritizedTasks, reference);
}
@NotNull
private <D extends CallableDescriptor> OverloadResolutionResults<D> doResolveCall(
@NotNull final BasicResolutionContext context,
@@ -264,148 +257,11 @@ public class CallResolver {
debugInfo.set(ResolutionDebugInfo.TASKS, prioritizedTasks);
TracingStrategy tracing = new TracingStrategy() {
@Override
public <D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCallImpl<D> 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 <D extends CallableDescriptor> void recordAmbiguity(BindingTrace trace, Collection<ResolvedCallImpl<D>> candidates) {
Collection<D> descriptors = Sets.newHashSet();
for (ResolvedCallImpl<D> 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 <D extends CallableDescriptor> void ambiguity(@NotNull BindingTrace trace, @NotNull Collection<ResolvedCallImpl<D>> descriptors) {
trace.report(OVERLOAD_RESOLUTION_AMBIGUITY.on(context.call.getCallElement(), descriptors));
}
@Override
public <D extends CallableDescriptor> void noneApplicable(@NotNull BindingTrace trace, @NotNull Collection<ResolvedCallImpl<D>> 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<JetExpression> functionLiteralArguments) {
for (JetExpression functionLiteralArgument : functionLiteralArguments) {
trace.report(DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED.on(functionLiteralArgument));
}
}
};
TemporaryBindingTrace traceForFirstNonemptyCandidateSet = null;
OverloadResolutionResultsImpl<D> resultsForFirstNonemptyCandidateSet = null;
for (ResolutionTask<D> task : prioritizedTasks) {
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace);
BasicResolutionContext newContext = BasicResolutionContext.create(temporaryTrace, context.scope, task.getCall(), context.expectedType, context.dataFlowInfo);
OverloadResolutionResultsImpl<D> results = performResolutionGuardedForExtraFunctionLiteralArguments(new TaskResolutionContext<D>(task, tracing, newContext));
OverloadResolutionResultsImpl<D> results = performResolutionGuardedForExtraFunctionLiteralArguments(task.withTrace(temporaryTrace));
if (results.isSuccess()) {
temporaryTrace.commit();
@@ -435,8 +291,8 @@ public class CallResolver {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@NotNull
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> performResolutionGuardedForExtraFunctionLiteralArguments(TaskResolutionContext<D> context) {
OverloadResolutionResultsImpl<D> results = performResolution(context);
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> performResolutionGuardedForExtraFunctionLiteralArguments(ResolutionTask<D> task) {
OverloadResolutionResultsImpl<D> 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<OverloadResolutionResults.Code> 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<ResolvedCallImpl<D>> newCandidates = Lists.newArrayList();
for (ResolvedCallImpl<D> candidate : context.task.getCandidates()) {
for (ResolvedCallImpl<D> candidate : task.getCandidates()) {
newCandidates.add(ResolvedCallImpl.create(candidate.getCandidateDescriptor()));
}
ResolutionTask<D> newTask = new ResolutionTask<D>(newCandidates, new DelegatingCall(context.call) {
@NotNull
@Override
public List<JetExpression> getFunctionLiteralArguments() {
return Collections.emptyList();
}
}, context.dataFlowInfo);
BasicResolutionContext newBasicContext = BasicResolutionContext.create(TemporaryBindingTrace.create(context.trace), context.scope, context.call, context.expectedType, context.dataFlowInfo);
TaskResolutionContext<D> newContext = new TaskResolutionContext<D>(newTask, context.tracing, newBasicContext);
ResolutionTask<D> newContext = new ResolutionTask<D>(newCandidates, task.reference, TemporaryBindingTrace.create(task.trace), task.scope, new DelegatingCall(task.call) {
@NotNull
@Override
public List<JetExpression> getFunctionLiteralArguments() {
return Collections.emptyList();
}
}, task.expectedType, task.dataFlowInfo);
OverloadResolutionResultsImpl<D> 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 <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> performResolution(TaskResolutionContext<D> taskContext) {
for (ResolvedCallImpl<D> candidateCall : taskContext.task.getCandidates()) {
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> performResolution(ResolutionTask<D> task) {
for (ResolvedCallImpl<D> candidateCall : task.getCandidates()) {
D candidate = candidateCall.getCandidateDescriptor();
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(taskContext.trace);
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(task.trace);
candidateCall.setTrace(temporaryTrace);
CallResolutionContext<D> context = new CallResolutionContext<D>(candidateCall, taskContext, temporaryTrace, taskContext.tracing);
CallResolutionContext<D> context = new CallResolutionContext<D>(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<ResolvedCallImpl<D>> successfulCandidates = Sets.newLinkedHashSet();
Set<ResolvedCallImpl<D>> failedCandidates = Sets.newLinkedHashSet();
for (ResolvedCallImpl<D> candidateCall : taskContext.task.getCandidates()) {
for (ResolvedCallImpl<D> candidateCall : task.getCandidates()) {
ResolutionStatus status = candidateCall.getStatus();
if (status.isSuccess()) {
successfulCandidates.add(candidateCall);
@@ -582,9 +435,9 @@ public class CallResolver {
}
}
OverloadResolutionResultsImpl<D> results = computeResultAndReportErrors(taskContext.trace, taskContext.tracing, successfulCandidates, failedCandidates);
OverloadResolutionResultsImpl<D> 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<D extends CallableDescriptor> extends ResolutionContext {
/*package*/ final ResolutionTask<D> task;
/*package*/ final TracingStrategy tracing;
public TaskResolutionContext(ResolutionTask<D> 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<D extends CallableDescriptor> extends ResolutionContext {
/*package*/ final ResolvedCallImpl<D> candidateCall;
/*package*/ final TracingStrategy tracing;
public CallResolutionContext(ResolvedCallImpl<D> candidateCall, TaskResolutionContext<D> taskResolutionContext, BindingTrace trace, TracingStrategy tracing) {
super(trace, taskResolutionContext.scope, taskResolutionContext.task.getCall(), taskResolutionContext.expectedType, taskResolutionContext.dataFlowInfo);
public CallResolutionContext(ResolvedCallImpl<D> candidateCall, ResolutionTask<D> task, BindingTrace trace, TracingStrategy tracing) {
super(trace, task.scope, task.call, task.expectedType, task.dataFlowInfo);
this.candidateCall = candidateCall;
this.tracing = tracing;
}
@@ -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<D extends CallableDescriptor> {
private final Call call;
public class ResolutionTask<D extends CallableDescriptor> extends ResolutionContext {
private final Collection<ResolvedCallImpl<D>> candidates;
private final DataFlowInfo dataFlowInfo;
/*package*/ final JetReferenceExpression reference;
private DescriptorCheckStrategy checkingStrategy;
public ResolutionTask(
@NotNull Collection<ResolvedCallImpl<D>> candidates,
@NotNull Call call,
@NotNull DataFlowInfo dataFlowInfo
) {
public ResolutionTask(@NotNull Collection<ResolvedCallImpl<D>> 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<ResolvedCallImpl<D>> 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<D extends CallableDescriptor> {
return candidates;
}
@NotNull
public Call getCall() {
return call;
}
public void setCheckingStrategy(DescriptorCheckStrategy strategy) {
checkingStrategy = strategy;
}
@@ -72,7 +80,149 @@ public class ResolutionTask<D extends CallableDescriptor> {
return true;
}
public ResolutionTask<D> withTrace(BindingTrace newTrace) {
ResolutionTask<D> newTask = new ResolutionTask<D>(candidates, reference, newTrace, scope, call, expectedType, dataFlowInfo);
newTask.setCheckingStrategy(checkingStrategy);
return newTask;
}
public interface DescriptorCheckStrategy {
<D extends CallableDescriptor> boolean performAdvancedChecks(D descriptor, BindingTrace trace, TracingStrategy tracing);
}
public final TracingStrategy tracing = new TracingStrategy() {
@Override
public <D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCallImpl<D> 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 <D extends CallableDescriptor> void recordAmbiguity(BindingTrace trace, Collection<ResolvedCallImpl<D>> candidates) {
Collection<D> descriptors = Sets.newHashSet();
for (ResolvedCallImpl<D> 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 <D extends CallableDescriptor> void ambiguity(@NotNull BindingTrace trace, @NotNull Collection<ResolvedCallImpl<D>> descriptors) {
trace.report(OVERLOAD_RESOLUTION_AMBIGUITY.on(call.getCallElement(), descriptors));
}
@Override
public <D extends CallableDescriptor> void noneApplicable(@NotNull BindingTrace trace, @NotNull Collection<ResolvedCallImpl<D>> 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<JetExpression> functionLiteralArguments) {
for (JetExpression functionLiteralArgument : functionLiteralArguments) {
trace.report(DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED.on(functionLiteralArgument));
}
}
};
}
@@ -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<ResolutionTask<D>> computePrioritizedTasks(@NotNull JetScope scope, @NotNull Call call, @NotNull String name,
@NotNull BindingContext bindingContext, @NotNull DataFlowInfo dataFlowInfo) {
public List<ResolutionTask<D>> computePrioritizedTasks(@NotNull BasicResolutionContext context, @NotNull String name,
@NotNull JetReferenceExpression functionReference) {
List<ResolutionTask<D>> 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<ResolutionTask<D>> result, @NotNull AutoCastService autoCastService) {
private void doComputeTasks(JetScope scope, ReceiverDescriptor receiver, String name, List<ResolutionTask<D>> result, @NotNull BasicResolutionContext context, @NotNull JetReferenceExpression functionReference) {
AutoCastServiceImpl autoCastService = new AutoCastServiceImpl(context.dataFlowInfo, context.trace.getBindingContext());
DataFlowInfo dataFlowInfo = autoCastService.getDataFlowInfo();
List<ReceiverDescriptor> 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<D> memberExtensions = getExtensionsByName(implicitReceiver.getType().getMemberScope(), name);
List<ReceiverDescriptor> 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<ResolvedCallImpl<D>> 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.<D>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<ResolutionTask<D>> result, @NotNull Call call, @NotNull Collection<ResolvedCallImpl<D>> candidates, @NotNull DataFlowInfo dataFlowInfo) {
private void addTask(@NotNull List<ResolutionTask<D>> result, @NotNull Collection<ResolvedCallImpl<D>> candidates, @NotNull BasicResolutionContext context, @NotNull JetReferenceExpression functionReference) {
if (candidates.isEmpty()) return;
result.add(new ResolutionTask<D>(candidates, call, dataFlowInfo));
result.add(new ResolutionTask<D>(candidates, functionReference, context));
}
@NotNull