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:
@@ -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());
|
||||
}
|
||||
|
||||
+39
-51
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user