Better error reporting for overloads
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user