diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/SubstitutingScope.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/SubstitutingScope.java index bfa03e0f1be..8d4392eee57 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/SubstitutingScope.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/SubstitutingScope.java @@ -1,12 +1,15 @@ package org.jetbrains.jet.lang.resolve; +import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeSubstitutor; import java.util.Collection; +import java.util.Map; /** * @author abreslav @@ -15,7 +18,9 @@ public class SubstitutingScope implements JetScope { private final JetScope workerScope; private final TypeSubstitutor substitutor; - private Collection allDescriptors; + + private Map functionGroups = null; + private Collection allDescriptors = null; public SubstitutingScope(JetScope workerScope, @NotNull TypeSubstitutor substitutor) { this.workerScope = workerScope; @@ -58,11 +63,27 @@ public class SubstitutingScope implements JetScope { @NotNull @Override public FunctionGroup getFunctionGroup(@NotNull String name) { - FunctionGroup functionGroup = workerScope.getFunctionGroup(name); - if (substitutor.isEmpty() || functionGroup.isEmpty()) { - return functionGroup; + if (substitutor.isEmpty()) { + return workerScope.getFunctionGroup(name); } - return new LazySubstitutingFunctionGroup(substitutor, functionGroup); + if (functionGroups == null) { + functionGroups = Maps.newHashMap(); + } + FunctionGroup cachedGroup = functionGroups.get(name); + if (cachedGroup != null) { + return cachedGroup; + } + + FunctionGroup functionGroup = workerScope.getFunctionGroup(name); + FunctionGroup result; + if (functionGroup.isEmpty()) { + result = FunctionGroup.EMPTY; + } + else { + result = new LazySubstitutingFunctionGroup(substitutor, functionGroup); + } + functionGroups.put(name, result); + return result; } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java index 74a5f264c74..451fcf52346 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java @@ -291,7 +291,4 @@ public class TypeHierarchyResolver { } } } - - - } 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 6440ad0fef3..792948941c8 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 @@ -472,17 +472,9 @@ public class CallResolver { @NotNull private OverloadResolutionResult computeResultAndReportErrors(BindingTrace trace, TracingStrategy tracing, Map successfulCandidates, Set failedCandidates, Set dirtyCandidates, Map traces) { + // TODO : maybe it's better to filter overrides out first, and only then look for the maximally specific if (successfulCandidates.size() > 0) { - if (successfulCandidates.size() == 1) { - Map.Entry entry = successfulCandidates.entrySet().iterator().next(); - Descriptor functionDescriptor = entry.getKey(); - Descriptor result = entry.getValue(); - - TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor); - temporaryTrace.commit(); - return OverloadResolutionResult.success(result); - } - else { + if (successfulCandidates.size() != 1) { Map cleanCandidates = Maps.newLinkedHashMap(successfulCandidates); cleanCandidates.keySet().removeAll(dirtyCandidates); if (cleanCandidates.isEmpty()) { @@ -498,37 +490,41 @@ public class CallResolver { return OverloadResolutionResult.success(maximallySpecificGenericsDiscriminated); } + Set noOverrides = filterOverrides(successfulCandidates.keySet()); if (dirtyCandidates.isEmpty()) { - StringBuilder stringBuilder = new StringBuilder(); - for (Descriptor functionDescriptor : successfulCandidates.keySet()) { - stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append(" "); - } - - tracing.reportOverallResolutionError(trace, "Overload resolution ambiguity: " + stringBuilder); + tracing.reportOverallResolutionError(trace, "Overload resolution ambiguity: " + + makeErrorMessageForMultipleDescriptors(noOverrides)); } - - tracing.recordAmbiguity(trace, successfulCandidates.keySet()); - - return OverloadResolutionResult.ambiguity(successfulCandidates.keySet()); + + tracing.recordAmbiguity(trace, noOverrides); + + return OverloadResolutionResult.ambiguity(noOverrides); + } + else { + Map.Entry entry = successfulCandidates.entrySet().iterator().next(); + Descriptor functionDescriptor = entry.getKey(); + Descriptor result = entry.getValue(); + + TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor); + temporaryTrace.commit(); + return OverloadResolutionResult.success(result); } } else if (!failedCandidates.isEmpty()) { - if (failedCandidates.size() == 1) { - Descriptor functionDescriptor = failedCandidates.iterator().next(); - TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor); - temporaryTrace.commit(); - return OverloadResolutionResult.singleFailedCandidate(failedCandidates.iterator().next()); - } - else { - StringBuilder stringBuilder = new StringBuilder("\n"); - for (Descriptor functionDescriptor : failedCandidates) { - stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append("\n"); + if (failedCandidates.size() != 1) { + Set noOverrides = filterOverrides(failedCandidates); + if (noOverrides.size() != 1) { + tracing.reportOverallResolutionError(trace, "None of the following functions can be called with the arguments supplied: " + + makeErrorMessageForMultipleDescriptors(noOverrides)); + tracing.recordAmbiguity(trace, noOverrides); + return OverloadResolutionResult.manyFailedCandidates(noOverrides); } - - tracing.reportOverallResolutionError(trace, "None of the following functions can be called with the arguments supplied: " + stringBuilder); - tracing.recordAmbiguity(trace, failedCandidates); - return OverloadResolutionResult.manyFailedCandidates(failedCandidates); + failedCandidates = noOverrides; } + Descriptor functionDescriptor = failedCandidates.iterator().next(); + TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor); + temporaryTrace.commit(); + return OverloadResolutionResult.singleFailedCandidate(failedCandidates.iterator().next()); } else { tracing.reportUnresolvedReference(trace); @@ -536,6 +532,28 @@ public class CallResolver { } } + private StringBuilder makeErrorMessageForMultipleDescriptors(Set candidates) { + StringBuilder stringBuilder = new StringBuilder("\n"); + for (Descriptor functionDescriptor : candidates) { + stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append("\n"); + } + return stringBuilder; + } + + private Set filterOverrides(Set candidateSet) { + Set candidates = Sets.newLinkedHashSet(); + outerLoop: + for (Descriptor me : candidateSet) { + for (Descriptor other : candidateSet) { + if (OverloadingConflictResolver.overrides(other, me)) { + continue outerLoop; + } + } + candidates.add(me); + } + return candidates; + } + private boolean checkValueArgumentTypes(JetScope scope, JetTypeInferrer.Services temporaryServices, Map argumentsToParameters, Flag dirty, Function parameterMap) { boolean result = true; for (Map.Entry entry : argumentsToParameters.entrySet()) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java index 2a9887e3c2c..c25f75451b0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java @@ -120,7 +120,7 @@ import java.util.Set; return false; } - private boolean overrides(@NotNull Descriptor f, @NotNull Descriptor g) { + public static boolean overrides(@NotNull Descriptor f, @NotNull Descriptor g) { Set overriddenDescriptors = Sets.newHashSet(); getAllOverriddenDescriptors(f.getOriginal(), overriddenDescriptors); CallableDescriptor originalG = g.getOriginal(); @@ -130,7 +130,7 @@ import java.util.Set; return false; } - private void getAllOverriddenDescriptors(@NotNull CallableDescriptor current, @NotNull Set overriddenDescriptors) { + private static void getAllOverriddenDescriptors(@NotNull CallableDescriptor current, @NotNull Set overriddenDescriptors) { if (overriddenDescriptors.contains(current)) return; for (CallableDescriptor descriptor : current.getOriginal().getOverriddenDescriptors()) { getAllOverriddenDescriptors(descriptor, overriddenDescriptors); diff --git a/idea/testData/resolve/regressions/kt300.jet b/idea/testData/resolve/regressions/kt300.jet new file mode 100644 index 00000000000..aaaf340f3a7 --- /dev/null +++ b/idea/testData/resolve/regressions/kt300.jet @@ -0,0 +1,9 @@ +// KT-300 Overload ambiguity while accessing range + +class MyRange() : Range { + ~in~override fun contains(item: Int) = true +} + +fun foo(x: Int?, range: MyRange) { + x `in`in range // Int? found, but Int expected +} \ No newline at end of file