Ambiguities not reported when some types were not obtained (i.e. there are errors in the argument list)

This commit is contained in:
Andrey Breslav
2011-08-29 15:26:34 +04:00
parent d38fbbe2c6
commit 829910f2c2
6 changed files with 101 additions and 24 deletions
@@ -52,4 +52,5 @@ public class JetSemanticServices {
public JetTypeChecker getTypeChecker() {
return typeChecker;
}
}
}
@@ -3,6 +3,7 @@ package org.jetbrains.jet.lang.types;
import com.google.common.collect.Lists;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.*;
import java.util.Collections;
@@ -16,9 +17,15 @@ public class CallMaker {
private static class ExpressionValueArgument implements ValueArgument {
private final JetExpression expression;
private final PsiElement reportErrorsOn;
private ExpressionValueArgument(JetExpression expression) {
private ExpressionValueArgument(@NotNull JetExpression expression) {
this(expression, expression);
}
private ExpressionValueArgument(@Nullable JetExpression expression, @NotNull PsiElement reportErrorsOn) {
this.expression = expression;
this.reportErrorsOn = expression == null ? reportErrorsOn : expression;
}
@Override
@@ -49,7 +56,7 @@ public class CallMaker {
@NotNull
@Override
public PsiElement asElement() {
return expression;
return reportErrorsOn;
}
}
@@ -95,7 +102,7 @@ public class CallMaker {
public static Call makeCall(final JetExpression calleeExpression, final List<JetExpression> argumentExpressions) {
List<ValueArgument> arguments = Lists.newArrayList();
for (JetExpression argumentExpression : argumentExpressions) {
arguments.add(makeValueArgument(argumentExpression));
arguments.add(makeValueArgument(argumentExpression, calleeExpression));
}
return makeCallWithArguments(calleeExpression, arguments);
}
@@ -114,7 +121,11 @@ public class CallMaker {
return makeCall(arrayAccessExpression, arguments);
}
public static ValueArgument makeValueArgument(JetExpression expression) {
return new ExpressionValueArgument(expression);
public static ValueArgument makeValueArgument(@NotNull JetExpression expression) {
return makeValueArgument(expression, expression);
}
public static ValueArgument makeValueArgument(@Nullable JetExpression expression, @NotNull PsiElement reportErrorsOn) {
return new ExpressionValueArgument(expression, reportErrorsOn);
}
}
@@ -234,7 +234,7 @@ public class CallResolver {
private void addConstrtuctors(JetScope scope, String name, Collection<FunctionDescriptor> functions) {
ClassifierDescriptor classifier = scope.getClassifier(name);
if (classifier instanceof ClassDescriptor) {
if (classifier instanceof ClassDescriptor && !ErrorUtils.isError(classifier.getTypeConstructor())) {
ClassDescriptor classDescriptor = (ClassDescriptor) classifier;
functions.addAll(classDescriptor.getConstructors().getFunctionDescriptors());
}
@@ -454,6 +454,7 @@ public class CallResolver {
private FunctionDescriptor performResolution(@NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull JetType expectedType, @NotNull ResolutionTask task, @NotNull TracingStrategy tracing) {
Map<FunctionDescriptor, FunctionDescriptor> successfulCandidates = Maps.newLinkedHashMap();
Set<FunctionDescriptor> failedCandidates = Sets.newLinkedHashSet();
Set<FunctionDescriptor> dirtyCandidates = Sets.newLinkedHashSet();
Map<FunctionDescriptor, ConstraintSystem.Solution> solutions = Maps.newHashMap();
Map<FunctionDescriptor, TemporaryBindingTrace> traces = Maps.newHashMap();
@@ -463,6 +464,13 @@ public class CallResolver {
JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace);
tracing.bindFunctionReference(temporaryTrace, candidate);
if (ErrorUtils.isError(candidate)) {
successfulCandidates.put(candidate, candidate);
continue;
}
Flag dirty = new Flag(false);
Map<ValueArgument, ValueParameterDescriptor> argumentsToParameters = Maps.newHashMap();
boolean error = mapValueArgumentsToParameters(task, tracing, candidate, temporaryTrace, argumentsToParameters);
@@ -474,7 +482,7 @@ public class CallResolver {
if (task.getTypeArguments().isEmpty()) {
if (candidate.getTypeParameters().isEmpty()) {
if (checkValueArgumentTypes(scope, temporaryServices, argumentsToParameters, Functions.<ValueParameterDescriptor>identity())
if (checkValueArgumentTypes(scope, temporaryServices, argumentsToParameters, dirty, Functions.<ValueParameterDescriptor>identity())
&& checkReceiver(task, tracing, candidate, temporaryTrace)) {
successfulCandidates.put(candidate, candidate);
}
@@ -500,6 +508,9 @@ public class CallResolver {
if (type != null) {
constraintSystem.addSubtypingConstraint(type, valueParameterDescriptor.getOutType());
}
else {
dirty.setValue(true);
}
}
checkReceiverAbsence(task, tracing, candidate, temporaryTrace);
@@ -564,7 +575,7 @@ public class CallResolver {
return parameterMap.get(input.getOriginal());
}
};
if (checkValueArgumentTypes(scope, temporaryServices, argumentsToParameters, mapFunction)
if (checkValueArgumentTypes(scope, temporaryServices, argumentsToParameters, dirty, mapFunction)
&& checkReceiver(task, tracing, substitutedFunctionDescriptor, temporaryTrace)) {
successfulCandidates.put(candidate, substitutedFunctionDescriptor);
}
@@ -577,9 +588,30 @@ public class CallResolver {
tracing.reportWrongTypeArguments(temporaryTrace, "Number of type arguments does not match " + DescriptorRenderer.TEXT.render(candidate));
}
}
if (dirty.getValue()) {
dirtyCandidates.add(candidate);
}
}
return computeResultAndReportErrors(trace, tracing, successfulCandidates, failedCandidates, traces);
FunctionDescriptor functionDescriptor = computeResultAndReportErrors(trace, tracing, successfulCandidates, failedCandidates, dirtyCandidates, traces);
if (functionDescriptor == null) {
for (ValueArgument valueArgument : task.getValueArguments()) {
JetExpression argumentExpression = valueArgument.getArgumentExpression();
if (argumentExpression != null) {
typeInferrer.getServices(trace).getType(scope, argumentExpression, false, NO_EXPECTED_TYPE);
}
}
for (JetExpression expression : task.getFunctionLiteralArguments()) {
typeInferrer.getServices(trace).getType(scope, expression, false, NO_EXPECTED_TYPE);
}
for (JetTypeProjection typeProjection : task.getTypeArguments()) {
new TypeResolver(semanticServices, trace, true).resolveType(scope, typeProjection.getTypeReference());
}
}
return functionDescriptor;
}
private boolean checkReceiver(ResolutionTask task, TracingStrategy tracing, FunctionDescriptor candidate, TemporaryBindingTrace temporaryTrace) {
@@ -611,7 +643,8 @@ public class CallResolver {
return true;
}
private FunctionDescriptor computeResultAndReportErrors(BindingTrace trace, TracingStrategy tracing, Map<FunctionDescriptor, FunctionDescriptor> successfulCandidates, Set<FunctionDescriptor> failedCandidates, Map<FunctionDescriptor, TemporaryBindingTrace> traces) {
@Nullable
private FunctionDescriptor computeResultAndReportErrors(BindingTrace trace, TracingStrategy tracing, Map<FunctionDescriptor, FunctionDescriptor> successfulCandidates, Set<FunctionDescriptor> failedCandidates, Set<FunctionDescriptor> dirtyCandidates, Map<FunctionDescriptor, TemporaryBindingTrace> traces) {
if (successfulCandidates.size() > 0) {
if (successfulCandidates.size() == 1) {
Map.Entry<FunctionDescriptor, FunctionDescriptor> entry = successfulCandidates.entrySet().iterator().next();
@@ -633,12 +666,14 @@ public class CallResolver {
return maximallySpecificGenericsDiscriminated;
}
StringBuilder stringBuilder = new StringBuilder();
for (FunctionDescriptor functionDescriptor : successfulCandidates.keySet()) {
stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append(" ");
}
if (dirtyCandidates.isEmpty()) {
StringBuilder stringBuilder = new StringBuilder();
for (FunctionDescriptor functionDescriptor : successfulCandidates.keySet()) {
stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append(" ");
}
tracing.reportOverallResolutionError(trace, "Overload resolution ambiguity: " + stringBuilder);
tracing.reportOverallResolutionError(trace, "Overload resolution ambiguity: " + stringBuilder);
}
}
}
else if (!failedCandidates.isEmpty()) {
@@ -646,6 +681,7 @@ public class CallResolver {
FunctionDescriptor functionDescriptor = failedCandidates.iterator().next();
TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor);
temporaryTrace.commit();
return failedCandidates.iterator().next();
}
else {
StringBuilder stringBuilder = new StringBuilder();
@@ -659,10 +695,13 @@ public class CallResolver {
else {
tracing.reportUnresolvedFunctionReference(trace);
}
return null;
}
private boolean checkValueArgumentTypes(JetScope scope, JetTypeInferrer.Services temporaryServices, Map<ValueArgument, ValueParameterDescriptor> argumentsToParameters, Function<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap) {
private boolean checkValueArgumentTypes(JetScope scope, JetTypeInferrer.Services temporaryServices, Map<ValueArgument, ValueParameterDescriptor> argumentsToParameters, Flag dirty, Function<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap) {
for (Map.Entry<ValueArgument, ValueParameterDescriptor> entry : argumentsToParameters.entrySet()) {
ValueArgument valueArgument = entry.getKey();
ValueParameterDescriptor valueParameterDescriptor = entry.getValue();
@@ -672,9 +711,15 @@ public class CallResolver {
assert substitutedParameter != null;
JetType parameterType = substitutedParameter.getOutType();
JetType type = temporaryServices.getType(scope, valueArgument.getArgumentExpression(), false, parameterType);
if (type == null || !semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) {
return false;
JetExpression argumentExpression = valueArgument.getArgumentExpression();
if (argumentExpression != null) {
JetType type = temporaryServices.getType(scope, argumentExpression, false, parameterType);
if (type == null) {
dirty.setValue(true);
}
else if (!semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) {
return false;
}
}
}
return true;
@@ -769,7 +814,7 @@ public class CallResolver {
}
private boolean overrides(@NotNull FunctionDescriptor f, @NotNull FunctionDescriptor g) {
Set<? extends FunctionDescriptor> overriddenFunctions = f.getOverriddenFunctions();
Set<? extends FunctionDescriptor> overriddenFunctions = f.getOriginal().getOverriddenFunctions();
FunctionDescriptor originalG = g.getOriginal();
for (FunctionDescriptor overriddenFunction : overriddenFunctions) {
if (originalG.equals(overriddenFunction.getOriginal())) return true;
@@ -919,4 +964,20 @@ public class CallResolver {
return true;
}
private static class Flag {
private boolean flag;
public Flag(boolean flag) {
this.flag = flag;
}
public boolean getValue() {
return flag;
}
public void setValue(boolean flag) {
this.flag = flag;
}
}
}
@@ -181,6 +181,10 @@ public class ErrorUtils {
isError(type.getConstructor()));
}
public static boolean isError(@NotNull FunctionDescriptor candidate) {
return candidate.getContainingDeclaration() == getErrorClass();
}
private static class ErrorTypeImpl implements JetType {
private final TypeConstructor constructor;
@@ -651,7 +651,7 @@ public class JetTypeInferrer {
}
}
catch (ReenteringLazyValueComputationException e) {
context.trace.getErrorHandler().genericError(expression.getNode(), "Type inference has run into a recursive problem"); // TODO : message
context.trace.getErrorHandler().genericError(expression.getNode(), "Type checking has run into a recursive problem"); // TODO : message
result = null;
}
@@ -11,8 +11,8 @@ fun takeFirst(expr: StringBuilder): Char {
fun evaluateArg(expr: AbstractStringBuilder, numbers: ArrayList<Int>): Int {
if (expr.length() == 0) throw Exception("Syntax error: Character expected");
val c = takeFirst<error>(expr)</error>
if (c <error>>=</error> '0' && c <error><=</error> '9') {
val c = takeFirst(<error>expr</error>)
if (c >= '0' && c <= '9') {
val n = c - '0'
if (!numbers.contains(n)) throw Exception("You used incorrect number: " + n)
numbers.remove(n)