From 829910f2c21451dba7ed88b557b958fb00c24299 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 29 Aug 2011 15:26:34 +0400 Subject: [PATCH] Ambiguities not reported when some types were not obtained (i.e. there are errors in the argument list) --- .../jet/lang/JetSemanticServices.java | 3 +- .../jetbrains/jet/lang/types/CallMaker.java | 21 ++++- .../jet/lang/types/CallResolver.java | 91 ++++++++++++++++--- .../jetbrains/jet/lang/types/ErrorUtils.java | 4 + .../jet/lang/types/JetTypeInferrer.java | 2 +- .../checker/regression/DoubleDefine.jet | 4 +- 6 files changed, 101 insertions(+), 24 deletions(-) diff --git a/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java b/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java index 35be202837b..6d94973a3d4 100644 --- a/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java +++ b/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java @@ -52,4 +52,5 @@ public class JetSemanticServices { public JetTypeChecker getTypeChecker() { return typeChecker; } -} + +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/lang/types/CallMaker.java b/idea/src/org/jetbrains/jet/lang/types/CallMaker.java index 43c9ea9e94b..d01ad213406 100644 --- a/idea/src/org/jetbrains/jet/lang/types/CallMaker.java +++ b/idea/src/org/jetbrains/jet/lang/types/CallMaker.java @@ -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 argumentExpressions) { List 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); } } diff --git a/idea/src/org/jetbrains/jet/lang/types/CallResolver.java b/idea/src/org/jetbrains/jet/lang/types/CallResolver.java index 221615905a2..1bfc34f420d 100644 --- a/idea/src/org/jetbrains/jet/lang/types/CallResolver.java +++ b/idea/src/org/jetbrains/jet/lang/types/CallResolver.java @@ -234,7 +234,7 @@ public class CallResolver { private void addConstrtuctors(JetScope scope, String name, Collection 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 successfulCandidates = Maps.newLinkedHashMap(); Set failedCandidates = Sets.newLinkedHashSet(); + Set dirtyCandidates = Sets.newLinkedHashSet(); Map solutions = Maps.newHashMap(); Map 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 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.identity()) + if (checkValueArgumentTypes(scope, temporaryServices, argumentsToParameters, dirty, Functions.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 successfulCandidates, Set failedCandidates, Map traces) { + @Nullable + private FunctionDescriptor computeResultAndReportErrors(BindingTrace trace, TracingStrategy tracing, Map successfulCandidates, Set failedCandidates, Set dirtyCandidates, Map traces) { if (successfulCandidates.size() > 0) { if (successfulCandidates.size() == 1) { Map.Entry 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 argumentsToParameters, Function parameterMap) { + private boolean checkValueArgumentTypes(JetScope scope, JetTypeInferrer.Services temporaryServices, Map argumentsToParameters, Flag dirty, Function parameterMap) { for (Map.Entry 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 overriddenFunctions = f.getOverriddenFunctions(); + Set 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; + } + } } diff --git a/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java b/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java index aa127fd1875..0c159b76bb6 100644 --- a/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java +++ b/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java @@ -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; diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 6238e576780..480a8c0ff83 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -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; } diff --git a/idea/testData/checker/regression/DoubleDefine.jet b/idea/testData/checker/regression/DoubleDefine.jet index 3aa5205ccf1..ebbda575d07 100644 --- a/idea/testData/checker/regression/DoubleDefine.jet +++ b/idea/testData/checker/regression/DoubleDefine.jet @@ -11,8 +11,8 @@ fun takeFirst(expr: StringBuilder): Char { fun evaluateArg(expr: AbstractStringBuilder, numbers: ArrayList): Int { if (expr.length() == 0) throw Exception("Syntax error: Character expected"); - val c = takeFirst(expr) - if (c >= '0' && c <= '9') { + val c = takeFirst(expr) + if (c >= '0' && c <= '9') { val n = c - '0' if (!numbers.contains(n)) throw Exception("You used incorrect number: " + n) numbers.remove(n)