Ambiguities not reported when some types were not obtained (i.e. there are errors in the argument list)
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user