KT-300 Overload ambiguity while accessing range
This commit is contained in:
@@ -1,12 +1,15 @@
|
|||||||
package org.jetbrains.jet.lang.resolve;
|
package org.jetbrains.jet.lang.resolve;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
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.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
@@ -15,7 +18,9 @@ public class SubstitutingScope implements JetScope {
|
|||||||
|
|
||||||
private final JetScope workerScope;
|
private final JetScope workerScope;
|
||||||
private final TypeSubstitutor substitutor;
|
private final TypeSubstitutor substitutor;
|
||||||
private Collection<DeclarationDescriptor> allDescriptors;
|
|
||||||
|
private Map<String, FunctionGroup> functionGroups = null;
|
||||||
|
private Collection<DeclarationDescriptor> allDescriptors = null;
|
||||||
|
|
||||||
public SubstitutingScope(JetScope workerScope, @NotNull TypeSubstitutor substitutor) {
|
public SubstitutingScope(JetScope workerScope, @NotNull TypeSubstitutor substitutor) {
|
||||||
this.workerScope = workerScope;
|
this.workerScope = workerScope;
|
||||||
@@ -58,11 +63,27 @@ public class SubstitutingScope implements JetScope {
|
|||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public FunctionGroup getFunctionGroup(@NotNull String name) {
|
public FunctionGroup getFunctionGroup(@NotNull String name) {
|
||||||
FunctionGroup functionGroup = workerScope.getFunctionGroup(name);
|
if (substitutor.isEmpty()) {
|
||||||
if (substitutor.isEmpty() || functionGroup.isEmpty()) {
|
return workerScope.getFunctionGroup(name);
|
||||||
return functionGroup;
|
|
||||||
}
|
}
|
||||||
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
|
@NotNull
|
||||||
|
|||||||
@@ -291,7 +291,4 @@ public class TypeHierarchyResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -472,17 +472,9 @@ public class CallResolver {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private <Descriptor extends CallableDescriptor> OverloadResolutionResult<Descriptor> computeResultAndReportErrors(BindingTrace trace, TracingStrategy tracing, Map<Descriptor, Descriptor> successfulCandidates, Set<Descriptor> failedCandidates, Set<Descriptor> dirtyCandidates, Map<Descriptor, TemporaryBindingTrace> traces) {
|
private <Descriptor extends CallableDescriptor> OverloadResolutionResult<Descriptor> computeResultAndReportErrors(BindingTrace trace, TracingStrategy tracing, Map<Descriptor, Descriptor> successfulCandidates, Set<Descriptor> failedCandidates, Set<Descriptor> dirtyCandidates, Map<Descriptor, TemporaryBindingTrace> 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() > 0) {
|
||||||
if (successfulCandidates.size() == 1) {
|
if (successfulCandidates.size() != 1) {
|
||||||
Map.Entry<Descriptor, Descriptor> 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 {
|
|
||||||
Map<Descriptor, Descriptor> cleanCandidates = Maps.newLinkedHashMap(successfulCandidates);
|
Map<Descriptor, Descriptor> cleanCandidates = Maps.newLinkedHashMap(successfulCandidates);
|
||||||
cleanCandidates.keySet().removeAll(dirtyCandidates);
|
cleanCandidates.keySet().removeAll(dirtyCandidates);
|
||||||
if (cleanCandidates.isEmpty()) {
|
if (cleanCandidates.isEmpty()) {
|
||||||
@@ -498,37 +490,41 @@ public class CallResolver {
|
|||||||
return OverloadResolutionResult.success(maximallySpecificGenericsDiscriminated);
|
return OverloadResolutionResult.success(maximallySpecificGenericsDiscriminated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Set<Descriptor> noOverrides = filterOverrides(successfulCandidates.keySet());
|
||||||
if (dirtyCandidates.isEmpty()) {
|
if (dirtyCandidates.isEmpty()) {
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
tracing.reportOverallResolutionError(trace, "Overload resolution ambiguity: "
|
||||||
for (Descriptor functionDescriptor : successfulCandidates.keySet()) {
|
+ makeErrorMessageForMultipleDescriptors(noOverrides));
|
||||||
stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
tracing.reportOverallResolutionError(trace, "Overload resolution ambiguity: " + stringBuilder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing.recordAmbiguity(trace, successfulCandidates.keySet());
|
tracing.recordAmbiguity(trace, noOverrides);
|
||||||
|
|
||||||
return OverloadResolutionResult.ambiguity(successfulCandidates.keySet());
|
return OverloadResolutionResult.ambiguity(noOverrides);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Map.Entry<Descriptor, Descriptor> 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()) {
|
else if (!failedCandidates.isEmpty()) {
|
||||||
if (failedCandidates.size() == 1) {
|
if (failedCandidates.size() != 1) {
|
||||||
Descriptor functionDescriptor = failedCandidates.iterator().next();
|
Set<Descriptor> noOverrides = filterOverrides(failedCandidates);
|
||||||
TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor);
|
if (noOverrides.size() != 1) {
|
||||||
temporaryTrace.commit();
|
tracing.reportOverallResolutionError(trace, "None of the following functions can be called with the arguments supplied: "
|
||||||
return OverloadResolutionResult.singleFailedCandidate(failedCandidates.iterator().next());
|
+ makeErrorMessageForMultipleDescriptors(noOverrides));
|
||||||
}
|
tracing.recordAmbiguity(trace, noOverrides);
|
||||||
else {
|
return OverloadResolutionResult.manyFailedCandidates(noOverrides);
|
||||||
StringBuilder stringBuilder = new StringBuilder("\n");
|
|
||||||
for (Descriptor functionDescriptor : failedCandidates) {
|
|
||||||
stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append("\n");
|
|
||||||
}
|
}
|
||||||
|
failedCandidates = 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);
|
|
||||||
}
|
}
|
||||||
|
Descriptor functionDescriptor = failedCandidates.iterator().next();
|
||||||
|
TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor);
|
||||||
|
temporaryTrace.commit();
|
||||||
|
return OverloadResolutionResult.singleFailedCandidate(failedCandidates.iterator().next());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tracing.reportUnresolvedReference(trace);
|
tracing.reportUnresolvedReference(trace);
|
||||||
@@ -536,6 +532,28 @@ public class CallResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private <Descriptor extends CallableDescriptor> StringBuilder makeErrorMessageForMultipleDescriptors(Set<Descriptor> candidates) {
|
||||||
|
StringBuilder stringBuilder = new StringBuilder("\n");
|
||||||
|
for (Descriptor functionDescriptor : candidates) {
|
||||||
|
stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append("\n");
|
||||||
|
}
|
||||||
|
return stringBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private <Descriptor extends CallableDescriptor> Set<Descriptor> filterOverrides(Set<Descriptor> candidateSet) {
|
||||||
|
Set<Descriptor> 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<ValueArgument, ValueParameterDescriptor> argumentsToParameters, Flag dirty, Function<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap) {
|
private boolean checkValueArgumentTypes(JetScope scope, JetTypeInferrer.Services temporaryServices, Map<ValueArgument, ValueParameterDescriptor> argumentsToParameters, Flag dirty, Function<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap) {
|
||||||
boolean result = true;
|
boolean result = true;
|
||||||
for (Map.Entry<ValueArgument, ValueParameterDescriptor> entry : argumentsToParameters.entrySet()) {
|
for (Map.Entry<ValueArgument, ValueParameterDescriptor> entry : argumentsToParameters.entrySet()) {
|
||||||
|
|||||||
+2
-2
@@ -120,7 +120,7 @@ import java.util.Set;
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private <Descriptor extends CallableDescriptor> boolean overrides(@NotNull Descriptor f, @NotNull Descriptor g) {
|
public static <Descriptor extends CallableDescriptor> boolean overrides(@NotNull Descriptor f, @NotNull Descriptor g) {
|
||||||
Set<CallableDescriptor> overriddenDescriptors = Sets.newHashSet();
|
Set<CallableDescriptor> overriddenDescriptors = Sets.newHashSet();
|
||||||
getAllOverriddenDescriptors(f.getOriginal(), overriddenDescriptors);
|
getAllOverriddenDescriptors(f.getOriginal(), overriddenDescriptors);
|
||||||
CallableDescriptor originalG = g.getOriginal();
|
CallableDescriptor originalG = g.getOriginal();
|
||||||
@@ -130,7 +130,7 @@ import java.util.Set;
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getAllOverriddenDescriptors(@NotNull CallableDescriptor current, @NotNull Set<CallableDescriptor> overriddenDescriptors) {
|
private static void getAllOverriddenDescriptors(@NotNull CallableDescriptor current, @NotNull Set<CallableDescriptor> overriddenDescriptors) {
|
||||||
if (overriddenDescriptors.contains(current)) return;
|
if (overriddenDescriptors.contains(current)) return;
|
||||||
for (CallableDescriptor descriptor : current.getOriginal().getOverriddenDescriptors()) {
|
for (CallableDescriptor descriptor : current.getOriginal().getOverriddenDescriptors()) {
|
||||||
getAllOverriddenDescriptors(descriptor, overriddenDescriptors);
|
getAllOverriddenDescriptors(descriptor, overriddenDescriptors);
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// KT-300 Overload ambiguity while accessing range
|
||||||
|
|
||||||
|
class MyRange() : Range<Int> {
|
||||||
|
~in~override fun contains(item: Int) = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(x: Int?, range: MyRange) {
|
||||||
|
x `in`in range // Int? found, but Int expected
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user