From 1ed0c11ce2ddd3c9f8c023bd19231f55d5f3684d Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 21 Mar 2011 21:14:52 +0300 Subject: [PATCH] Better error reporting for overloads --- .../resolve/OverloadResolutionResult.java | 40 +++++++++++++------ .../jet/lang/resolve/OverloadResolver.java | 9 ++++- .../lang/resolve/WritableFunctionGroup.java | 30 ++++++++++---- .../jetbrains/jet/lang/types/ErrorType.java | 11 ++--- .../jet/lang/types/FunctionGroup.java | 12 ++---- .../jet/lang/types/JetTypeInferrer.java | 3 +- .../types/LazySubstitutingFunctionGroup.java | 11 +++-- .../jetbrains/jet/resolve/JetResolveTest.java | 5 ++- 8 files changed, 80 insertions(+), 41 deletions(-) diff --git a/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolutionResult.java b/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolutionResult.java index c8afc4591b4..f49c7bd22ce 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolutionResult.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolutionResult.java @@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.types.FunctionDescriptor; import java.util.Collection; +import java.util.Collections; /** * @author abreslav @@ -24,38 +25,43 @@ public class OverloadResolutionResult { boolean isSuccess() { return success; } + } public static OverloadResolutionResult success(@NotNull FunctionDescriptor functionDescriptor) { - return new OverloadResolutionResult(Code.SUCCESS, functionDescriptor); + return new OverloadResolutionResult(Code.SUCCESS, Collections.singleton(functionDescriptor)); } public static OverloadResolutionResult nameNotFound() { - return new OverloadResolutionResult(Code.NAME_NOT_FOUND, null); + return new OverloadResolutionResult(Code.NAME_NOT_FOUND, Collections.emptyList()); } - public static OverloadResolutionResult singleFunctionArgumentMismatch(FunctionDescriptor functionDescriptor) { - return new OverloadResolutionResult(Code.SINGLE_FUNCTION_ARGUMENT_MISMATCH, functionDescriptor); + return new OverloadResolutionResult(Code.SINGLE_FUNCTION_ARGUMENT_MISMATCH, Collections.singleton(functionDescriptor)); } public static OverloadResolutionResult ambiguity(Collection functionDescriptors) { - return new OverloadResolutionResult(Code.AMBIGUITY, null); // TODO + return new OverloadResolutionResult(Code.AMBIGUITY, functionDescriptors); } - private final FunctionDescriptor functionDescriptor; + private final Collection functionDescriptors; + private final Code resultCode; - public OverloadResolutionResult(@NotNull Code resultCode, FunctionDescriptor functionDescriptor) { - this.functionDescriptor = functionDescriptor; + public OverloadResolutionResult(@NotNull Code resultCode, @NotNull Collection functionDescriptors) { + this.functionDescriptors = functionDescriptors; this.resultCode = resultCode; } - @NotNull // This is done on purpose, despite the fact that errors may not carry a descriptor: - // one should not call this method at all in that case + @NotNull + public Collection getFunctionDescriptors() { + return functionDescriptors; + } + + @NotNull public FunctionDescriptor getFunctionDescriptor() { - assert functionDescriptor != null; - return functionDescriptor; + assert singleFunction(); + return functionDescriptors.iterator().next(); } @NotNull @@ -71,5 +77,15 @@ public class OverloadResolutionResult { return isSuccess() || resultCode == Code.SINGLE_FUNCTION_ARGUMENT_MISMATCH; } + public boolean isNothing() { + return resultCode == Code.NAME_NOT_FOUND; + } + public boolean isAmbiguity() { + return resultCode == Code.AMBIGUITY; + } + + public OverloadResolutionResult newContents(@NotNull Collection functionDescriptors) { + return new OverloadResolutionResult(resultCode, functionDescriptors); + } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java index d0175e79f38..24c8ecc2143 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java @@ -37,7 +37,11 @@ public class OverloadResolver { @NotNull @Override public OverloadResolutionResult getFunctionDescriptorForPositionedArguments(@NotNull final List typeArguments, @NotNull List positionedValueArgumentTypes) { - Collection possiblyApplicableFunctions = functionGroup.getPossiblyApplicableFunctions(typeArguments, positionedValueArgumentTypes); + OverloadResolutionResult resolutionResult = functionGroup.getPossiblyApplicableFunctions(typeArguments, positionedValueArgumentTypes); + if (!resolutionResult.isAmbiguity() && !resolutionResult.isSuccess()) return resolutionResult; + + Collection possiblyApplicableFunctions = resolutionResult.getFunctionDescriptors(); + if (possiblyApplicableFunctions.isEmpty()) { return OverloadResolutionResult.nameNotFound(); // TODO : it may be found, only the number of params did not match } @@ -85,6 +89,9 @@ public class OverloadResolver { } if (applicable.size() == 0) { + if (resolutionResult.singleFunction()) { + return OverloadResolutionResult.singleFunctionArgumentMismatch(resolutionResult.getFunctionDescriptor()); + } return OverloadResolutionResult.nameNotFound(); } else if (applicable.size() == 1) { return OverloadResolutionResult.success(applicable.get(0)); diff --git a/idea/src/org/jetbrains/jet/lang/resolve/WritableFunctionGroup.java b/idea/src/org/jetbrains/jet/lang/resolve/WritableFunctionGroup.java index 74e1646b2e1..7bac48a0e03 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/WritableFunctionGroup.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/WritableFunctionGroup.java @@ -1,10 +1,12 @@ package org.jetbrains.jet.lang.resolve; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.lang.types.FunctionDescriptor; +import org.jetbrains.jet.lang.types.FunctionDescriptorUtil; +import org.jetbrains.jet.lang.types.FunctionGroup; +import org.jetbrains.jet.lang.types.JetType; import java.util.ArrayList; -import java.util.Collection; import java.util.List; /** @@ -12,7 +14,7 @@ import java.util.List; */ public class WritableFunctionGroup implements FunctionGroup { private final String name; - private Collection functionDescriptors; + private List functionDescriptors; public WritableFunctionGroup(String name) { this.name = name; @@ -36,7 +38,7 @@ public class WritableFunctionGroup implements FunctionGroup { } @NotNull - private Collection getFunctionDescriptors() { + private List getFunctionDescriptors() { if (functionDescriptors == null) { functionDescriptors = new ArrayList(); } @@ -45,11 +47,14 @@ public class WritableFunctionGroup implements FunctionGroup { @NotNull @Override - public Collection getPossiblyApplicableFunctions(@NotNull List typeArguments, @NotNull List positionedValueArgumentTypes) { + public OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List typeArguments, @NotNull List positionedValueArgumentTypes) { + List functionDescriptors = getFunctionDescriptors(); + if (functionDescriptors.isEmpty()) return OverloadResolutionResult.nameNotFound(); + int typeArgCount = typeArguments.size(); int valueArgCount = positionedValueArgumentTypes.size(); - Collection result = new ArrayList(); - for (FunctionDescriptor functionDescriptor : getFunctionDescriptors()) { + List result = new ArrayList(); + for (FunctionDescriptor functionDescriptor : functionDescriptors) { // TODO : type argument inference breaks this logic if (functionDescriptor.getTypeParameters().size() == typeArgCount) { if (FunctionDescriptorUtil.getMinimumArity(functionDescriptor) <= valueArgCount && @@ -58,7 +63,16 @@ public class WritableFunctionGroup implements FunctionGroup { } } } - return result; + if (result.isEmpty()) { + assert !functionDescriptors.isEmpty(); + if (functionDescriptors.size() == 1) { + return OverloadResolutionResult.singleFunctionArgumentMismatch(functionDescriptors.get(0)); + } + } + if (result.size() == 1) { + return OverloadResolutionResult.success(result.get(0)); + } + return OverloadResolutionResult.ambiguity(result); } @Override diff --git a/idea/src/org/jetbrains/jet/lang/types/ErrorType.java b/idea/src/org/jetbrains/jet/lang/types/ErrorType.java index fae8ccf5338..06a8686075e 100644 --- a/idea/src/org/jetbrains/jet/lang/types/ErrorType.java +++ b/idea/src/org/jetbrains/jet/lang/types/ErrorType.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.types; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.resolve.JetScope; +import org.jetbrains.jet.lang.resolve.OverloadResolutionResult; import java.util.*; @@ -67,9 +68,9 @@ public class ErrorType { @NotNull @Override - public Collection getPossiblyApplicableFunctions(@NotNull List typeArguments, @NotNull List positionedValueArgumentTypes) { + public OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List typeArguments, @NotNull List positionedValueArgumentTypes) { List typeParameters = Collections.emptyList(); - return createErrorFunction(typeParameters, positionedValueArgumentTypes); + return OverloadResolutionResult.success(createErrorFunction(typeParameters, positionedValueArgumentTypes)); } @Override @@ -87,13 +88,13 @@ public class ErrorType { private static final PropertyDescriptor ERROR_PROPERTY = new PropertyDescriptorImpl(ERROR_CLASS, Collections.emptyList(), "", createErrorType("")); - private static Collection createErrorFunction(List typeParameters, List positionedValueArgumentTypes) { + private static FunctionDescriptor createErrorFunction(List typeParameters, List positionedValueArgumentTypes) { FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl(ERROR_CLASS, Collections.emptyList(), ""); - return Collections.singletonList(functionDescriptor.initialize( + return functionDescriptor.initialize( typeParameters, getValueParameters(functionDescriptor, positionedValueArgumentTypes), createErrorType("") - )); + ); } private static FunctionDescriptor createErrorFunction(int typeParameterCount, Map valueParameters) { diff --git a/idea/src/org/jetbrains/jet/lang/types/FunctionGroup.java b/idea/src/org/jetbrains/jet/lang/types/FunctionGroup.java index 4083e1e027b..bd91cf6c892 100644 --- a/idea/src/org/jetbrains/jet/lang/types/FunctionGroup.java +++ b/idea/src/org/jetbrains/jet/lang/types/FunctionGroup.java @@ -1,9 +1,8 @@ package org.jetbrains.jet.lang.types; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.resolve.OverloadResolutionResult; -import java.util.Collection; -import java.util.Collections; import java.util.List; /** @@ -19,9 +18,8 @@ public interface FunctionGroup extends Named { @NotNull @Override - public Collection getPossiblyApplicableFunctions(@NotNull List typeArguments, @NotNull List positionedValueArgumentTypes) { - return Collections.emptyList(); -// return OverloadResolutionResult.nameNotFound(); + public OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List typeArguments, @NotNull List positionedValueArgumentTypes) { + return OverloadResolutionResult.nameNotFound(); } @Override @@ -36,9 +34,7 @@ public interface FunctionGroup extends Named { String getName(); @NotNull - Collection getPossiblyApplicableFunctions(@NotNull List typeArguments, @NotNull List positionedValueArgumentTypes); -// @NotNull -// OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List typeArguments, @NotNull List positionedValueArgumentTypes); + OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List typeArguments, @NotNull List positionedValueArgumentTypes); boolean isEmpty(); } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 2e8575863f1..81c492f5f2e 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -9,6 +9,7 @@ import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lexer.JetTokens; +import org.jetbrains.jet.resolve.DescriptorUtil; import java.util.*; @@ -241,7 +242,7 @@ public class JetTypeInferrer { case SINGLE_FUNCTION_ARGUMENT_MISMATCH: if (argumentList != null) { // TODO : More helpful message. NOTE: there's a separate handling for this for constructors - semanticServices.getErrorHandler().genericError(argumentList.getNode(), "Arguments do not match " + resolutionResult.getFunctionDescriptor()); + semanticServices.getErrorHandler().genericError(argumentList.getNode(), "Arguments do not match " + DescriptorUtil.renderPresentableText(resolutionResult.getFunctionDescriptor())); } else { semanticServices.getErrorHandler().unresolvedReference(referenceExpression); diff --git a/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionGroup.java b/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionGroup.java index ad18b8aa1fe..e0a214d011e 100644 --- a/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionGroup.java +++ b/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionGroup.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.lang.types; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.resolve.OverloadResolutionResult; import java.util.ArrayList; import java.util.Collection; @@ -27,17 +28,19 @@ public class LazySubstitutingFunctionGroup implements FunctionGroup { @NotNull @Override - public Collection getPossiblyApplicableFunctions(@NotNull List typeArguments, @NotNull List positionedValueArgumentTypes) { - Collection possiblyApplicableFunctions = functionGroup.getPossiblyApplicableFunctions(typeArguments, positionedValueArgumentTypes); + public OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List typeArguments, @NotNull List positionedValueArgumentTypes) { + OverloadResolutionResult resolutionResult = functionGroup.getPossiblyApplicableFunctions(typeArguments, positionedValueArgumentTypes); + if (resolutionResult.isNothing()) return resolutionResult; + Collection result = new ArrayList(); - for (FunctionDescriptor function : possiblyApplicableFunctions) { + for (FunctionDescriptor function : resolutionResult.getFunctionDescriptors()) { if (substitutionContext.isEmpty()) { result.add(function); } else { result.add(new LazySubstitutingFunctionDescriptor(substitutionContext, function)); } } - return result; + return resolutionResult.newContents(result); } @Override diff --git a/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java b/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java index f7c68427baa..12e201e18c5 100644 --- a/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java +++ b/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java @@ -10,6 +10,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.resolve.OverloadResolutionResult; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.parsing.JetParsingTest; @@ -93,8 +94,8 @@ public class JetResolveTest extends ExtensibleResolveTestCase { private FunctionDescriptor standardFunction(ClassDescriptor classDescriptor, List typeArguments, String name, JetType... parameterType) { FunctionGroup functionGroup = classDescriptor.getMemberScope(typeArguments).getFunctionGroup(name); List parameterTypeList = Arrays.asList(parameterType); - Collection functions = functionGroup.getPossiblyApplicableFunctions(Collections.emptyList(), parameterTypeList); - for (FunctionDescriptor function : functions) { + OverloadResolutionResult functions = functionGroup.getPossiblyApplicableFunctions(Collections.emptyList(), parameterTypeList); + for (FunctionDescriptor function : functions.getFunctionDescriptors()) { List unsubstitutedValueParameters = function.getUnsubstitutedValueParameters(); for (int i = 0, unsubstitutedValueParametersSize = unsubstitutedValueParameters.size(); i < unsubstitutedValueParametersSize; i++) { ValueParameterDescriptor unsubstitutedValueParameter = unsubstitutedValueParameters.get(i);