From e9c8be84494d3d2e405768c5b98124e73023fb42 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Fri, 9 Nov 2012 15:50:16 +0400 Subject: [PATCH] complete type inference only for one candidate (the most specific) to avoid exponential resolve of value arguments for several candidates where type inference is incomplete (or depends on expected type) --- .../jet/lang/resolve/calls/CallResolver.java | 60 ++++++++++++------- .../lang/resolve/calls/CandidateResolver.java | 11 +--- .../OverloadResolutionResultsImpl.java | 2 +- .../results/ResolutionResultsHandler.java | 30 ++++++---- .../calls/results/ResolutionStatus.java | 1 + .../cannotCompleteResolveAmbiguity.kt | 8 +++ ...notCompleteResolveFunctionLiteralsNoUse.kt | 6 ++ ...cannotCompleteResolveNoInfoForParameter.kt | 10 ++++ .../cannotCompleteResolveNoneApplicable.kt | 8 +++ ...nnotCompleteResolveWithFunctionLiterals.kt | 9 +++ ...utionForOverloadResolutionWithAmbiguity.kt | 2 +- ...tionForOverloadResolutionWithErrorTypes.kt | 2 +- .../checkers/JetDiagnosticsTestGenerated.java | 26 +++++++- 13 files changed, 126 insertions(+), 49 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/inference/cannotCompleteResolveAmbiguity.kt create mode 100644 compiler/testData/diagnostics/tests/inference/cannotCompleteResolveFunctionLiteralsNoUse.kt create mode 100644 compiler/testData/diagnostics/tests/inference/cannotCompleteResolveNoInfoForParameter.kt create mode 100644 compiler/testData/diagnostics/tests/inference/cannotCompleteResolveNoneApplicable.kt create mode 100644 compiler/testData/diagnostics/tests/inference/cannotCompleteResolveWithFunctionLiterals.kt 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 1dd74d2b265..94aab41033c 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 @@ -16,6 +16,8 @@ package org.jetbrains.jet.lang.resolve.calls; +import com.google.common.base.Function; +import com.google.common.collect.Collections2; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.intellij.openapi.progress.ProgressIndicatorProvider; @@ -28,10 +30,7 @@ import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace; -import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults; -import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl; -import org.jetbrains.jet.lang.resolve.calls.results.ResolutionDebugInfo; -import org.jetbrains.jet.lang.resolve.calls.results.ResolutionResultsHandler; +import org.jetbrains.jet.lang.resolve.calls.results.*; import org.jetbrains.jet.lang.resolve.calls.tasks.*; import org.jetbrains.jet.lang.resolve.calls.util.DelegatingCall; import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor; @@ -305,27 +304,42 @@ public class CallResolver { @NotNull OverloadResolutionResults resultsWithIncompleteTypeInference, @NotNull TracingStrategy tracing ) { - if (resultsWithIncompleteTypeInference.getResultCode() != OverloadResolutionResults.Code.INCOMPLETE_TYPE_INFERENCE) + if (resultsWithIncompleteTypeInference.getResultCode() != OverloadResolutionResults.Code.INCOMPLETE_TYPE_INFERENCE) { return resultsWithIncompleteTypeInference; - Set> successful = Sets.newLinkedHashSet(); - Set> failed = Sets.newLinkedHashSet(); - for (ResolvedCall call : resultsWithIncompleteTypeInference.getResultingCalls()) { - if (!(call instanceof ResolvedCallImpl)) continue; - ResolvedCallImpl resolvedCall = CallResolverUtil.copy((ResolvedCallImpl) call, context); - if (!resolvedCall.hasUnknownTypeParameters()) { - if (resolvedCall.getStatus().isSuccess()) { - successful.add(resolvedCall); - } - else { - failed.add(resolvedCall); - } - continue; - } - candidateResolver.completeTypeInferenceDependentOnExpectedTypeForCall( - CallResolutionContext.create(context, tracing, resolvedCall), successful, failed); } - OverloadResolutionResultsImpl results = ResolutionResultsHandler.INSTANCE.computeResultAndReportErrors(context.trace, tracing, successful, - failed); + + Set> candidates = Sets.newLinkedHashSet(); + Set> incompleteCalls = Sets.newLinkedHashSet(); + for (ResolvedCall cachedCall : resultsWithIncompleteTypeInference.getResultingCalls()) { + if (cachedCall instanceof ResolvedCallImpl) { + ResolvedCallImpl resolvedCall = (ResolvedCallImpl) cachedCall; + if (resolvedCall.hasUnknownTypeParameters()) { + ResolvedCallImpl copy = CallResolverUtil.copy(resolvedCall, context); + incompleteCalls.add(copy); + candidates.add(copy); + continue; + } + } + candidates.add((ResolvedCallWithTrace) cachedCall); + } + ResolvedCallWithTrace maximallySpecific = OverloadingConflictResolver.INSTANCE.findMaximallySpecific(incompleteCalls, false); + if (maximallySpecific != null) { + candidateResolver.completeTypeInferenceDependentOnExpectedTypeForCall( + CallResolutionContext.create(context, tracing, (ResolvedCallImpl) maximallySpecific)); + for (ResolvedCallWithTrace callWithUnknownTypeParameters : incompleteCalls) { + if (callWithUnknownTypeParameters != maximallySpecific) { + ((ResolvedCallImpl) callWithUnknownTypeParameters).addStatus(ResolutionStatus.OTHER_ERROR); + } + } + } + else { + for (ResolvedCallWithTrace callWithUnknownTypeParameters : incompleteCalls) { + ResolvedCallImpl resolvedCall = (ResolvedCallImpl) callWithUnknownTypeParameters; + resolvedCall.addStatus(ResolutionStatus.INCOMPLETE_TYPE_INFERENCE); + } + } + OverloadResolutionResultsImpl results = ResolutionResultsHandler.INSTANCE.computeResultAndReportErrors( + context.trace, tracing, candidates); if (!results.isSingleResult()) { candidateResolver.checkTypesWithNoCallee(context); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java index be9e37cae2e..953265a3b23 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java @@ -198,9 +198,7 @@ public class CandidateResolver { } public void completeTypeInferenceDependentOnExpectedTypeForCall( - CallResolutionContext context, - Set> successful, - Set> failed + CallResolutionContext context ) { ResolvedCallImpl resolvedCall = context.candidateCall; assert resolvedCall.hasUnknownTypeParameters(); @@ -247,7 +245,6 @@ public class CandidateResolver { context.expectedType), constraintSystemWithoutExpectedTypeConstraint); resolvedCall.addStatus(ResolutionStatus.OTHER_ERROR); - failed.add(resolvedCall); return; } @@ -257,12 +254,8 @@ public class CandidateResolver { checkBounds(resolvedCall, constraintSystem, resolvedCall.getTrace(), context.tracing); resolvedCall.setHasUnknownTypeParameters(false); - if (resolvedCall.getStatus().isSuccess() || resolvedCall.getStatus() == ResolutionStatus.UNKNOWN_STATUS) { + if (resolvedCall.getStatus() == ResolutionStatus.UNKNOWN_STATUS) { resolvedCall.addStatus(ResolutionStatus.SUCCESS); - successful.add(resolvedCall); - } - else { - failed.add(resolvedCall); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadResolutionResultsImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadResolutionResultsImpl.java index 7cd5613a25e..3c6784418cd 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadResolutionResultsImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadResolutionResultsImpl.java @@ -59,7 +59,7 @@ public class OverloadResolutionResultsImpl impleme return new OverloadResolutionResultsImpl(Code.AMBIGUITY, candidates); } - private static OverloadResolutionResultsImpl incompleteTypeInference(Collection> candidates) { + public static OverloadResolutionResultsImpl incompleteTypeInference(Collection> candidates) { return new OverloadResolutionResultsImpl(Code.INCOMPLETE_TYPE_INFERENCE, candidates); } 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 62ddf874f0a..a826a16b63e 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 @@ -31,9 +31,7 @@ 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; -import static org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus.SEVERITY_LEVELS; -import static org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus.STRONG_ERROR; -import static org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus.UNKNOWN_STATUS; +import static org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus.*; public class ResolutionResultsHandler { public static ResolutionResultsHandler INSTANCE = new ResolutionResultsHandler(); @@ -48,27 +46,30 @@ public class ResolutionResultsHandler { ) { Set> successfulCandidates = Sets.newLinkedHashSet(); Set> failedCandidates = Sets.newLinkedHashSet(); + Set> incompleteCandidates = Sets.newLinkedHashSet(); for (ResolvedCallWithTrace candidateCall : candidates) { ResolutionStatus status = candidateCall.getStatus(); + assert status != UNKNOWN_STATUS : "No resolution for " + candidateCall.getCandidateDescriptor(); if (status.isSuccess()) { successfulCandidates.add(candidateCall); } - else { - assert status != UNKNOWN_STATUS : "No resolution for " + candidateCall.getCandidateDescriptor(); - if (candidateCall.getStatus() != STRONG_ERROR) { - failedCandidates.add(candidateCall); - } + else if (status == INCOMPLETE_TYPE_INFERENCE) { + incompleteCandidates.add(candidateCall); + } + else if (candidateCall.getStatus() != STRONG_ERROR) { + failedCandidates.add(candidateCall); } } - return computeResultAndReportErrors(trace, tracing, successfulCandidates, failedCandidates); + return computeResultAndReportErrors(trace, tracing, successfulCandidates, failedCandidates, incompleteCandidates); } @NotNull - public OverloadResolutionResultsImpl computeResultAndReportErrors( + private OverloadResolutionResultsImpl computeResultAndReportErrors( @NotNull BindingTrace trace, @NotNull TracingStrategy tracing, @NotNull Set> successfulCandidates, - @NotNull Set> failedCandidates + @NotNull Set> failedCandidates, + @NotNull Set> incompleteCandidates ) { // TODO : maybe it's better to filter overrides out first, and only then look for the maximally specific @@ -87,6 +88,13 @@ public class ResolutionResultsHandler { } return results; } + else if (!incompleteCandidates.isEmpty()) { + assert incompleteCandidates.size() > 1 : + "One incomplete candidate should have been chosen as maximally specific and completed earlier"; + tracing.cannotCompleteResolve(trace, incompleteCandidates); + tracing.recordAmbiguity(trace, incompleteCandidates); + return OverloadResolutionResultsImpl.incompleteTypeInference(incompleteCandidates); + } else if (!failedCandidates.isEmpty()) { if (failedCandidates.size() != 1) { // This is needed when there are several overloads some of which are OK but for nullability of the receiver, diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/ResolutionStatus.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/ResolutionStatus.java index aca2a2dc7ad..68cb51864c3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/ResolutionStatus.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/ResolutionStatus.java @@ -26,6 +26,7 @@ public enum ResolutionStatus { UNSAFE_CALL_ERROR, OTHER_ERROR, STRONG_ERROR, + INCOMPLETE_TYPE_INFERENCE, SUCCESS(true); @SuppressWarnings("unchecked") diff --git a/compiler/testData/diagnostics/tests/inference/cannotCompleteResolveAmbiguity.kt b/compiler/testData/diagnostics/tests/inference/cannotCompleteResolveAmbiguity.kt new file mode 100644 index 00000000000..926e7f7d6e8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/cannotCompleteResolveAmbiguity.kt @@ -0,0 +1,8 @@ +package f + +fun g(i: Int, a: Any): List {throw Exception()} +fun g(a: Any, i: Int): Collection {throw Exception()} + +fun test() { + val c: List = g(1, 1) +} diff --git a/compiler/testData/diagnostics/tests/inference/cannotCompleteResolveFunctionLiteralsNoUse.kt b/compiler/testData/diagnostics/tests/inference/cannotCompleteResolveFunctionLiteralsNoUse.kt new file mode 100644 index 00000000000..a8c504424cd --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/cannotCompleteResolveFunctionLiteralsNoUse.kt @@ -0,0 +1,6 @@ +package f + +fun h(i: Int, a: Any, r: R, f: (Boolean) -> Int) = 1 +fun h(a: Any, i: Int, r: R, f: (Boolean) -> Int) = 1 + +fun test() = h(1, 1, 1, { b -> 42 }) diff --git a/compiler/testData/diagnostics/tests/inference/cannotCompleteResolveNoInfoForParameter.kt b/compiler/testData/diagnostics/tests/inference/cannotCompleteResolveNoInfoForParameter.kt new file mode 100644 index 00000000000..1cacf692c67 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/cannotCompleteResolveNoInfoForParameter.kt @@ -0,0 +1,10 @@ +package f + +fun f(i: Int, c: Collection): List {throw Exception()} +fun f(a: Any, l: List): Collection {throw Exception()} + +fun test(l: List) { + f(1, emptyList()) +} + +fun emptyList(): List {throw Exception()} diff --git a/compiler/testData/diagnostics/tests/inference/cannotCompleteResolveNoneApplicable.kt b/compiler/testData/diagnostics/tests/inference/cannotCompleteResolveNoneApplicable.kt new file mode 100644 index 00000000000..c90ab3fd4a4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/cannotCompleteResolveNoneApplicable.kt @@ -0,0 +1,8 @@ +package f + +fun f(i: Int, t: T, c: MutableCollection) {} +fun f(a: Any, t: T, l: MutableList) {} + +fun test(l: List) { + f(1, "", l) +} diff --git a/compiler/testData/diagnostics/tests/inference/cannotCompleteResolveWithFunctionLiterals.kt b/compiler/testData/diagnostics/tests/inference/cannotCompleteResolveWithFunctionLiterals.kt new file mode 100644 index 00000000000..3b323da7881 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/cannotCompleteResolveWithFunctionLiterals.kt @@ -0,0 +1,9 @@ +package f + +fun h(f: (Boolean) -> R) = 1 +fun h(f: (String) -> R) = 2 + +fun test() = h{ i -> getAnswer() } + +fun getAnswer() = 42 + diff --git a/compiler/testData/diagnostics/tests/substitutions/upperBoundsSubstitutionForOverloadResolutionWithAmbiguity.kt b/compiler/testData/diagnostics/tests/substitutions/upperBoundsSubstitutionForOverloadResolutionWithAmbiguity.kt index eb116a27a17..72fdca57d20 100644 --- a/compiler/testData/diagnostics/tests/substitutions/upperBoundsSubstitutionForOverloadResolutionWithAmbiguity.kt +++ b/compiler/testData/diagnostics/tests/substitutions/upperBoundsSubstitutionForOverloadResolutionWithAmbiguity.kt @@ -10,5 +10,5 @@ import foo.* fun f(l: List) {} fun test(l: List) { - f(l) + f(l) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/substitutions/upperBoundsSubstitutionForOverloadResolutionWithErrorTypes.kt b/compiler/testData/diagnostics/tests/substitutions/upperBoundsSubstitutionForOverloadResolutionWithErrorTypes.kt index 765c1e0ae93..b336add5933 100644 --- a/compiler/testData/diagnostics/tests/substitutions/upperBoundsSubstitutionForOverloadResolutionWithErrorTypes.kt +++ b/compiler/testData/diagnostics/tests/substitutions/upperBoundsSubstitutionForOverloadResolutionWithErrorTypes.kt @@ -3,5 +3,5 @@ fun f1(l: List2): T {thr fun f1(c: Collection): T{throw Exception()} fun test(l: List) { - f1(l) + f1(l) } \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index d2e208c88d8..06e479da797 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -1733,9 +1733,29 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/inference/arrayConstructor.kt"); } - @TestMetadata("cannotCompleteResolve.kt") - public void testCannotCompleteResolve() throws Exception { - doTest("compiler/testData/diagnostics/tests/inference/cannotCompleteResolve.kt"); + @TestMetadata("cannotCompleteResolveAmbiguity.kt") + public void testCannotCompleteResolveAmbiguity() throws Exception { + doTest("compiler/testData/diagnostics/tests/inference/cannotCompleteResolveAmbiguity.kt"); + } + + @TestMetadata("cannotCompleteResolveFunctionLiteralsNoUse.kt") + public void testCannotCompleteResolveFunctionLiteralsNoUse() throws Exception { + doTest("compiler/testData/diagnostics/tests/inference/cannotCompleteResolveFunctionLiteralsNoUse.kt"); + } + + @TestMetadata("cannotCompleteResolveNoInfoForParameter.kt") + public void testCannotCompleteResolveNoInfoForParameter() throws Exception { + doTest("compiler/testData/diagnostics/tests/inference/cannotCompleteResolveNoInfoForParameter.kt"); + } + + @TestMetadata("cannotCompleteResolveNoneApplicable.kt") + public void testCannotCompleteResolveNoneApplicable() throws Exception { + doTest("compiler/testData/diagnostics/tests/inference/cannotCompleteResolveNoneApplicable.kt"); + } + + @TestMetadata("cannotCompleteResolveWithFunctionLiterals.kt") + public void testCannotCompleteResolveWithFunctionLiterals() throws Exception { + doTest("compiler/testData/diagnostics/tests/inference/cannotCompleteResolveWithFunctionLiterals.kt"); } @TestMetadata("completeInferenceIfManyFailed.kt")