Better error reporting for overloads

This commit is contained in:
Andrey Breslav
2011-03-21 21:14:52 +03:00
parent 7601e71571
commit 1ed0c11ce2
8 changed files with 80 additions and 41 deletions
@@ -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.<FunctionDescriptor>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<FunctionDescriptor> functionDescriptors) {
return new OverloadResolutionResult(Code.AMBIGUITY, null); // TODO
return new OverloadResolutionResult(Code.AMBIGUITY, functionDescriptors);
}
private final FunctionDescriptor functionDescriptor;
private final Collection<FunctionDescriptor> functionDescriptors;
private final Code resultCode;
public OverloadResolutionResult(@NotNull Code resultCode, FunctionDescriptor functionDescriptor) {
this.functionDescriptor = functionDescriptor;
public OverloadResolutionResult(@NotNull Code resultCode, @NotNull Collection<FunctionDescriptor> 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<FunctionDescriptor> 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<FunctionDescriptor> functionDescriptors) {
return new OverloadResolutionResult(resultCode, functionDescriptors);
}
}
@@ -37,7 +37,11 @@ public class OverloadResolver {
@NotNull
@Override
public OverloadResolutionResult getFunctionDescriptorForPositionedArguments(@NotNull final List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
Collection<FunctionDescriptor> possiblyApplicableFunctions = functionGroup.getPossiblyApplicableFunctions(typeArguments, positionedValueArgumentTypes);
OverloadResolutionResult resolutionResult = functionGroup.getPossiblyApplicableFunctions(typeArguments, positionedValueArgumentTypes);
if (!resolutionResult.isAmbiguity() && !resolutionResult.isSuccess()) return resolutionResult;
Collection<FunctionDescriptor> 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));
@@ -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<FunctionDescriptor> functionDescriptors;
private List<FunctionDescriptor> functionDescriptors;
public WritableFunctionGroup(String name) {
this.name = name;
@@ -36,7 +38,7 @@ public class WritableFunctionGroup implements FunctionGroup {
}
@NotNull
private Collection<FunctionDescriptor> getFunctionDescriptors() {
private List<FunctionDescriptor> getFunctionDescriptors() {
if (functionDescriptors == null) {
functionDescriptors = new ArrayList<FunctionDescriptor>();
}
@@ -45,11 +47,14 @@ public class WritableFunctionGroup implements FunctionGroup {
@NotNull
@Override
public Collection<FunctionDescriptor> getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
public OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
List<FunctionDescriptor> functionDescriptors = getFunctionDescriptors();
if (functionDescriptors.isEmpty()) return OverloadResolutionResult.nameNotFound();
int typeArgCount = typeArguments.size();
int valueArgCount = positionedValueArgumentTypes.size();
Collection<FunctionDescriptor> result = new ArrayList<FunctionDescriptor>();
for (FunctionDescriptor functionDescriptor : getFunctionDescriptors()) {
List<FunctionDescriptor> result = new ArrayList<FunctionDescriptor>();
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
@@ -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<FunctionDescriptor> getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
public OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
List<TypeParameterDescriptor> typeParameters = Collections.<TypeParameterDescriptor>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.<Attribute>emptyList(), "<ERROR PROPERTY>", createErrorType("<ERROR PROPERTY TYPE>"));
private static Collection<FunctionDescriptor> createErrorFunction(List<TypeParameterDescriptor> typeParameters, List<JetType> positionedValueArgumentTypes) {
private static FunctionDescriptor createErrorFunction(List<TypeParameterDescriptor> typeParameters, List<JetType> positionedValueArgumentTypes) {
FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl(ERROR_CLASS, Collections.<Attribute>emptyList(), "<ERROR FUNCTION>");
return Collections.singletonList(functionDescriptor.initialize(
return functionDescriptor.initialize(
typeParameters,
getValueParameters(functionDescriptor, positionedValueArgumentTypes),
createErrorType("<ERROR FUNCTION RETURN>")
));
);
}
private static FunctionDescriptor createErrorFunction(int typeParameterCount, Map<String, JetType> valueParameters) {
@@ -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<FunctionDescriptor> getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
return Collections.emptyList();
// return OverloadResolutionResult.nameNotFound();
public OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
return OverloadResolutionResult.nameNotFound();
}
@Override
@@ -36,9 +34,7 @@ public interface FunctionGroup extends Named {
String getName();
@NotNull
Collection<FunctionDescriptor> getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes);
// @NotNull
// OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes);
OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes);
boolean isEmpty();
}
@@ -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);
@@ -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<FunctionDescriptor> getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
Collection<FunctionDescriptor> possiblyApplicableFunctions = functionGroup.getPossiblyApplicableFunctions(typeArguments, positionedValueArgumentTypes);
public OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
OverloadResolutionResult resolutionResult = functionGroup.getPossiblyApplicableFunctions(typeArguments, positionedValueArgumentTypes);
if (resolutionResult.isNothing()) return resolutionResult;
Collection<FunctionDescriptor> result = new ArrayList<FunctionDescriptor>();
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
@@ -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<TypeProjection> typeArguments, String name, JetType... parameterType) {
FunctionGroup functionGroup = classDescriptor.getMemberScope(typeArguments).getFunctionGroup(name);
List<JetType> parameterTypeList = Arrays.asList(parameterType);
Collection<FunctionDescriptor> functions = functionGroup.getPossiblyApplicableFunctions(Collections.<JetType>emptyList(), parameterTypeList);
for (FunctionDescriptor function : functions) {
OverloadResolutionResult functions = functionGroup.getPossiblyApplicableFunctions(Collections.<JetType>emptyList(), parameterTypeList);
for (FunctionDescriptor function : functions.getFunctionDescriptors()) {
List<ValueParameterDescriptor> unsubstitutedValueParameters = function.getUnsubstitutedValueParameters();
for (int i = 0, unsubstitutedValueParametersSize = unsubstitutedValueParameters.size(); i < unsubstitutedValueParametersSize; i++) {
ValueParameterDescriptor unsubstitutedValueParameter = unsubstitutedValueParameters.get(i);