Check 'isDirty' for resolved calls replaced with check 'hasUnresolvedArguments' for call

Don't report 'cannotCompleteResolve' error if some arguments are unresolved (like 'ambiguity')
This commit is contained in:
Svetlana Isakova
2014-05-20 16:59:52 +04:00
parent a3e306b820
commit b2c2e1811c
6 changed files with 68 additions and 65 deletions
@@ -33,6 +33,7 @@ import org.jetbrains.jet.lang.psi.psiUtil.getParentByType
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody
import org.jetbrains.jet.lang.resolve.DescriptorUtils
import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor
import org.jetbrains.jet.lang.resolve.calls.ArgumentTypeResolver
/**
* For expressions like <code>a(), a[i], a.b.c(), +a, a + b, (a()), a(): Int, @label a()</code>
@@ -56,6 +57,16 @@ fun JetExpression.getCorrespondingCall(bindingContext: BindingContext): Call? {
return bindingContext[CALL, reference]
}
fun Call.hasUnresolvedArguments(bindingContext: BindingContext): Boolean {
val arguments = getValueArguments().map { it?.getArgumentExpression() }
return arguments.any {
argument ->
val expressionType = bindingContext[BindingContext.EXPRESSION_TYPE, argument]
argument != null && !ArgumentTypeResolver.isFunctionLiteralArgument(argument)
&& (expressionType == null || expressionType.isError())
}
}
public fun JetReturnExpression.getTargetFunctionDescriptor(bindingContext: BindingContext): FunctionDescriptor? {
val targetLabel = getTargetLabel()
if (targetLabel != null) return bindingContext[LABEL_TARGET, targetLabel]?.let { bindingContext[FUNCTION, it] }
@@ -566,7 +566,7 @@ public class CallResolver {
}
OverloadResolutionResultsImpl<F> results = ResolutionResultsHandler.INSTANCE.computeResultAndReportErrors(
task.trace, task.tracing, task.getResolvedCalls());
task, task.getResolvedCalls());
if (!results.isSingleResult() && !results.isIncomplete()) {
argumentTypeResolver.checkTypesWithNoCallee(task.toBasic());
}
@@ -19,13 +19,15 @@ package org.jetbrains.jet.lang.resolve.calls.results;
import com.google.common.collect.Sets;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.OverrideResolver;
import org.jetbrains.jet.lang.resolve.bindingContextUtil.BindingContextUtilPackage;
import org.jetbrains.jet.lang.resolve.calls.context.CheckValueArgumentsMode;
import org.jetbrains.jet.lang.resolve.calls.model.MutableResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.tasks.TracingStrategy;
import org.jetbrains.jet.lang.resolve.calls.util.UtilPackage;
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionTask;
import java.util.*;
import java.util.Collection;
import java.util.EnumSet;
import java.util.Set;
import static org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl.MAP_TO_CANDIDATE;
import static org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl.MAP_TO_RESULT;
@@ -38,8 +40,7 @@ public class ResolutionResultsHandler {
@NotNull
public <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> computeResultAndReportErrors(
@NotNull BindingTrace trace,
@NotNull TracingStrategy tracing,
@NotNull ResolutionTask task,
@NotNull Collection<MutableResolvedCall<D>> candidates
) {
Set<MutableResolvedCall<D>> successfulCandidates = Sets.newLinkedHashSet();
@@ -65,25 +66,24 @@ public class ResolutionResultsHandler {
// TODO : maybe it's better to filter overrides out first, and only then look for the maximally specific
if (!successfulCandidates.isEmpty() || !incompleteCandidates.isEmpty()) {
return computeSuccessfulResult(trace, tracing, successfulCandidates, incompleteCandidates);
return computeSuccessfulResult(task, successfulCandidates, incompleteCandidates);
}
else if (!failedCandidates.isEmpty()) {
return computeFailedResult(trace, tracing, failedCandidates);
return computeFailedResult(task, failedCandidates);
}
if (!candidatesWithWrongReceiver.isEmpty()) {
tracing.unresolvedReferenceWrongReceiver(trace, candidatesWithWrongReceiver);
task.tracing.unresolvedReferenceWrongReceiver(task.trace, candidatesWithWrongReceiver);
return OverloadResolutionResultsImpl.candidatesWithWrongReceiver(candidatesWithWrongReceiver);
}
tracing.unresolvedReference(trace);
task.tracing.unresolvedReference(task.trace);
return OverloadResolutionResultsImpl.nameNotFound();
}
@NotNull
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> computeSuccessfulResult(
BindingTrace trace,
TracingStrategy tracing,
Set<MutableResolvedCall<D>> successfulCandidates,
Set<MutableResolvedCall<D>> incompleteCandidates
@NotNull ResolutionTask task,
@NotNull Set<MutableResolvedCall<D>> successfulCandidates,
@NotNull Set<MutableResolvedCall<D>> incompleteCandidates
) {
Set<MutableResolvedCall<D>> successfulAndIncomplete = Sets.newLinkedHashSet();
successfulAndIncomplete.addAll(successfulCandidates);
@@ -91,21 +91,27 @@ public class ResolutionResultsHandler {
OverloadResolutionResultsImpl<D> results = chooseAndReportMaximallySpecific(successfulAndIncomplete, true);
if (results.isSingleResult()) {
MutableResolvedCall<D> resultingCall = results.getResultingCall();
resultingCall.getTrace().moveAllMyDataTo(trace);
resultingCall.getTrace().moveAllMyDataTo(task.trace);
if (resultingCall.getStatus() == INCOMPLETE_TYPE_INFERENCE) {
return OverloadResolutionResultsImpl.incompleteTypeInference(resultingCall);
}
}
if (results.isAmbiguity()) {
tracing.recordAmbiguity(trace, results.getResultingCalls());
if (allIncomplete(results.getResultingCalls())) {
tracing.cannotCompleteResolve(trace, results.getResultingCalls());
return OverloadResolutionResultsImpl.incompleteTypeInference(results.getResultingCalls());
}
task.tracing.recordAmbiguity(task.trace, results.getResultingCalls());
boolean allCandidatesIncomplete = allIncomplete(results.getResultingCalls());
// This check is needed for the following case:
// x.foo(unresolved) -- if there are multiple foo's, we'd report an ambiguity, and it does not make sense here
if (allClean(results.getResultingCalls())) {
tracing.ambiguity(trace, results.getResultingCalls());
if (task.checkArguments == CheckValueArgumentsMode.DISABLED ||
!BindingContextUtilPackage.hasUnresolvedArguments(task.call, task.trace.getBindingContext())) {
if (allCandidatesIncomplete) {
task.tracing.cannotCompleteResolve(task.trace, results.getResultingCalls());
}
else {
task.tracing.ambiguity(task.trace, results.getResultingCalls());
}
}
if (allCandidatesIncomplete) {
return OverloadResolutionResultsImpl.incompleteTypeInference(results.getResultingCalls());
}
}
return results;
@@ -113,9 +119,8 @@ public class ResolutionResultsHandler {
@NotNull
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> computeFailedResult(
BindingTrace trace,
TracingStrategy tracing,
Set<MutableResolvedCall<D>> failedCandidates
@NotNull ResolutionTask task,
@NotNull Set<MutableResolvedCall<D>> failedCandidates
) {
if (failedCandidates.size() != 1) {
// This is needed when there are several overloads some of which are OK but for nullability of the receiver,
@@ -131,12 +136,12 @@ public class ResolutionResultsHandler {
if (!thisLevel.isEmpty()) {
OverloadResolutionResultsImpl<D> results = chooseAndReportMaximallySpecific(thisLevel, false);
if (results.isSingleResult()) {
results.getResultingCall().getTrace().moveAllMyDataTo(trace);
results.getResultingCall().getTrace().moveAllMyDataTo(task.trace);
return OverloadResolutionResultsImpl.singleFailedCandidate(results.getResultingCall());
}
tracing.noneApplicable(trace, results.getResultingCalls());
tracing.recordAmbiguity(trace, results.getResultingCalls());
task.tracing.noneApplicable(task.trace, results.getResultingCalls());
task.tracing.recordAmbiguity(task.trace, results.getResultingCalls());
return OverloadResolutionResultsImpl.manyFailedCandidates(results.getResultingCalls());
}
}
@@ -145,8 +150,8 @@ public class ResolutionResultsHandler {
Set<MutableResolvedCall<D>> noOverrides = OverrideResolver.filterOutOverridden(failedCandidates, MAP_TO_CANDIDATE);
if (noOverrides.size() != 1) {
tracing.noneApplicable(trace, noOverrides);
tracing.recordAmbiguity(trace, noOverrides);
task.tracing.noneApplicable(task.trace, noOverrides);
task.tracing.recordAmbiguity(task.trace, noOverrides);
return OverloadResolutionResultsImpl.manyFailedCandidates(noOverrides);
}
@@ -154,17 +159,10 @@ public class ResolutionResultsHandler {
}
MutableResolvedCall<D> failed = failedCandidates.iterator().next();
failed.getTrace().moveAllMyDataTo(trace);
failed.getTrace().moveAllMyDataTo(task.trace);
return OverloadResolutionResultsImpl.singleFailedCandidate(failed);
}
private static <D extends CallableDescriptor> boolean allClean(@NotNull Collection<MutableResolvedCall<D>> results) {
for (MutableResolvedCall<D> result : results) {
if (UtilPackage.isDirty(result)) return false;
}
return true;
}
private static <D extends CallableDescriptor> boolean allIncomplete(@NotNull Collection<MutableResolvedCall<D>> results) {
for (MutableResolvedCall<D> result : results) {
if (result.getStatus() != INCOMPLETE_TYPE_INFERENCE) return false;
@@ -181,24 +179,14 @@ public class ResolutionResultsHandler {
return OverloadResolutionResultsImpl.success(candidates.iterator().next());
}
Set<MutableResolvedCall<D>> cleanCandidates = Sets.newLinkedHashSet(candidates);
for (Iterator<MutableResolvedCall<D>> iterator = cleanCandidates.iterator(); iterator.hasNext(); ) {
MutableResolvedCall<D> candidate = iterator.next();
if (UtilPackage.isDirty(candidate)) {
iterator.remove();
}
}
if (cleanCandidates.isEmpty()) {
cleanCandidates = candidates;
}
MutableResolvedCall<D> maximallySpecific = OverloadingConflictResolver.INSTANCE.findMaximallySpecific(cleanCandidates, false);
MutableResolvedCall<D> maximallySpecific = OverloadingConflictResolver.INSTANCE.findMaximallySpecific(candidates, false);
if (maximallySpecific != null) {
return OverloadResolutionResultsImpl.success(maximallySpecific);
}
if (discriminateGenerics) {
MutableResolvedCall<D> maximallySpecificGenericsDiscriminated = OverloadingConflictResolver.INSTANCE.findMaximallySpecific(cleanCandidates, true);
MutableResolvedCall<D> maximallySpecificGenericsDiscriminated = OverloadingConflictResolver.INSTANCE.findMaximallySpecific(
candidates, true);
if (maximallySpecificGenericsDiscriminated != null) {
return OverloadResolutionResultsImpl.success(maximallySpecificGenericsDiscriminated);
}
@@ -18,14 +18,10 @@ package org.jetbrains.jet.lang.resolve.calls.util
import org.jetbrains.jet.lang.descriptors.CallableDescriptor
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults
import org.jetbrains.jet.lang.resolve.calls.model.ArgumentUnmapped
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument
import org.jetbrains.jet.lang.resolve.calls.model.ArgumentMapping
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor
import org.jetbrains.jet.lang.resolve.calls.model.ArgumentMatch
import org.jetbrains.jet.lang.resolve.calls.model.ArgumentMatchStatus
import java.util.ArrayList
import org.jetbrains.jet.lang.psi.Call
import org.jetbrains.jet.lang.psi.ValueArgument
@@ -52,15 +48,6 @@ public fun <D : CallableDescriptor> ResolvedCall<D>.hasTypeMismatchErrorOnParame
}
}
fun <D : CallableDescriptor> ResolvedCall<D>.isDirty(): Boolean {
return getValueArguments().values()
.flatMap { it.getArguments() }
.any { argument ->
val argumentMapping = getArgumentMapping(argument)
argumentMapping is ArgumentMatch && argumentMapping.status == ArgumentMatchStatus.ARGUMENT_HAS_NO_TYPE
}
}
fun Call.getAllValueArguments(): List<ValueArgument> {
val arguments = getValueArguments() +
getFunctionLiteralArguments().map { functionLiteral -> CallMaker.makeValueArgument(functionLiteral) }
@@ -0,0 +1,12 @@
//!DIAGNOSTICS: -UNUSED_PARAMETER
fun foo<T>(i: Int, t: T) {}
fun foo<T>(s: String, t: T) {}
fun bar(i: Int) {}
fun bar(s: String) {}
fun test() {
foo(<!UNRESOLVED_REFERENCE!>rrr<!>, 1)
bar(<!UNRESOLVED_REFERENCE!>rrr<!>)
}
@@ -3791,6 +3791,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest("compiler/testData/diagnostics/tests/incompleteCode/typeParameterOnLhsOfDot.kt");
}
@TestMetadata("unresolvedArguments.kt")
public void testUnresolvedArguments() throws Exception {
doTest("compiler/testData/diagnostics/tests/incompleteCode/unresolvedArguments.kt");
}
@TestMetadata("variableDeclarationInSelector.kt")
public void testVariableDeclarationInSelector() throws Exception {
doTest("compiler/testData/diagnostics/tests/incompleteCode/variableDeclarationInSelector.kt");