diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.kt index 1841ed6dfd7..b7615b955a2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.kt @@ -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 a(), a[i], a.b.c(), +a, a + b, (a()), a(): Int, @label a() @@ -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] } 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 40f0b964d80..01236a192aa 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 @@ -566,7 +566,7 @@ public class CallResolver { } OverloadResolutionResultsImpl results = ResolutionResultsHandler.INSTANCE.computeResultAndReportErrors( - task.trace, task.tracing, task.getResolvedCalls()); + task, task.getResolvedCalls()); if (!results.isSingleResult() && !results.isIncomplete()) { argumentTypeResolver.checkTypesWithNoCallee(task.toBasic()); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/ResolutionResultsHandler.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/ResolutionResultsHandler.java index f69c3474117..c7e679d5c05 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/ResolutionResultsHandler.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/ResolutionResultsHandler.java @@ -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 OverloadResolutionResultsImpl computeResultAndReportErrors( - @NotNull BindingTrace trace, - @NotNull TracingStrategy tracing, + @NotNull ResolutionTask task, @NotNull Collection> candidates ) { Set> 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 OverloadResolutionResultsImpl computeSuccessfulResult( - BindingTrace trace, - TracingStrategy tracing, - Set> successfulCandidates, - Set> incompleteCandidates + @NotNull ResolutionTask task, + @NotNull Set> successfulCandidates, + @NotNull Set> incompleteCandidates ) { Set> successfulAndIncomplete = Sets.newLinkedHashSet(); successfulAndIncomplete.addAll(successfulCandidates); @@ -91,21 +91,27 @@ public class ResolutionResultsHandler { OverloadResolutionResultsImpl results = chooseAndReportMaximallySpecific(successfulAndIncomplete, true); if (results.isSingleResult()) { MutableResolvedCall 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 OverloadResolutionResultsImpl computeFailedResult( - BindingTrace trace, - TracingStrategy tracing, - Set> failedCandidates + @NotNull ResolutionTask task, + @NotNull Set> 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 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> 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 failed = failedCandidates.iterator().next(); - failed.getTrace().moveAllMyDataTo(trace); + failed.getTrace().moveAllMyDataTo(task.trace); return OverloadResolutionResultsImpl.singleFailedCandidate(failed); } - private static boolean allClean(@NotNull Collection> results) { - for (MutableResolvedCall result : results) { - if (UtilPackage.isDirty(result)) return false; - } - return true; - } - private static boolean allIncomplete(@NotNull Collection> results) { for (MutableResolvedCall result : results) { if (result.getStatus() != INCOMPLETE_TYPE_INFERENCE) return false; @@ -181,24 +179,14 @@ public class ResolutionResultsHandler { return OverloadResolutionResultsImpl.success(candidates.iterator().next()); } - Set> cleanCandidates = Sets.newLinkedHashSet(candidates); - for (Iterator> iterator = cleanCandidates.iterator(); iterator.hasNext(); ) { - MutableResolvedCall candidate = iterator.next(); - if (UtilPackage.isDirty(candidate)) { - iterator.remove(); - } - } - - if (cleanCandidates.isEmpty()) { - cleanCandidates = candidates; - } - MutableResolvedCall maximallySpecific = OverloadingConflictResolver.INSTANCE.findMaximallySpecific(cleanCandidates, false); + MutableResolvedCall maximallySpecific = OverloadingConflictResolver.INSTANCE.findMaximallySpecific(candidates, false); if (maximallySpecific != null) { return OverloadResolutionResultsImpl.success(maximallySpecific); } if (discriminateGenerics) { - MutableResolvedCall maximallySpecificGenericsDiscriminated = OverloadingConflictResolver.INSTANCE.findMaximallySpecific(cleanCandidates, true); + MutableResolvedCall maximallySpecificGenericsDiscriminated = OverloadingConflictResolver.INSTANCE.findMaximallySpecific( + candidates, true); if (maximallySpecificGenericsDiscriminated != null) { return OverloadResolutionResultsImpl.success(maximallySpecificGenericsDiscriminated); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/resolvedCallUtil.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/resolvedCallUtil.kt index 371d2beb274..fa484ef4b93 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/resolvedCallUtil.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/resolvedCallUtil.kt @@ -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 ResolvedCall.hasTypeMismatchErrorOnParame } } -fun ResolvedCall.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 { val arguments = getValueArguments() + getFunctionLiteralArguments().map { functionLiteral -> CallMaker.makeValueArgument(functionLiteral) } diff --git a/compiler/testData/diagnostics/tests/incompleteCode/unresolvedArguments.kt b/compiler/testData/diagnostics/tests/incompleteCode/unresolvedArguments.kt new file mode 100644 index 00000000000..a27667e5d69 --- /dev/null +++ b/compiler/testData/diagnostics/tests/incompleteCode/unresolvedArguments.kt @@ -0,0 +1,12 @@ +//!DIAGNOSTICS: -UNUSED_PARAMETER + +fun foo(i: Int, t: T) {} +fun foo(s: String, t: T) {} + +fun bar(i: Int) {} +fun bar(s: String) {} + +fun test() { + foo(rrr, 1) + bar(rrr) +} diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 3212c3fcc7c..022c1c99dcc 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -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");