Overload resolution with type inference
This commit is contained in:
@@ -44,6 +44,7 @@ public interface JetNodeTypes {
|
|||||||
JetNodeType TYPE_ARGUMENT_LIST = new JetNodeType("TYPE_ARGUMENT_LIST", JetTypeArgumentList.class);
|
JetNodeType TYPE_ARGUMENT_LIST = new JetNodeType("TYPE_ARGUMENT_LIST", JetTypeArgumentList.class);
|
||||||
JetNodeType VALUE_ARGUMENT_LIST = new JetNodeType("VALUE_ARGUMENT_LIST", JetValueArgumentList.class);
|
JetNodeType VALUE_ARGUMENT_LIST = new JetNodeType("VALUE_ARGUMENT_LIST", JetValueArgumentList.class);
|
||||||
JetNodeType VALUE_ARGUMENT = new JetNodeType("VALUE_ARGUMENT", JetValueArgument.class);
|
JetNodeType VALUE_ARGUMENT = new JetNodeType("VALUE_ARGUMENT", JetValueArgument.class);
|
||||||
|
JetNodeType VALUE_ARGUMENT_NAME = new JetNodeType("VALUE_ARGUMENT_LIST", JetValueArgumentName.class);
|
||||||
JetNodeType TYPE_REFERENCE = new JetNodeType("TYPE_REFERENCE", JetTypeReference.class);
|
JetNodeType TYPE_REFERENCE = new JetNodeType("TYPE_REFERENCE", JetTypeReference.class);
|
||||||
JetNodeType LABELED_TUPLE_ENTRY = new JetNodeType("LABELED_TUPLE_ENTRY");
|
JetNodeType LABELED_TUPLE_ENTRY = new JetNodeType("LABELED_TUPLE_ENTRY");
|
||||||
JetNodeType LABELED_TUPLE_TYPE_ENTRY = new JetNodeType("LABELED_TUPLE_TYPE_ENTRY");
|
JetNodeType LABELED_TUPLE_TYPE_ENTRY = new JetNodeType("LABELED_TUPLE_TYPE_ENTRY");
|
||||||
|
|||||||
@@ -20,4 +20,7 @@ public interface ValueParameterDescriptor extends VariableDescriptor {
|
|||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
JetType getOutType();
|
JetType getOutType();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
ValueParameterDescriptor getOriginal();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1625,7 +1625,11 @@ public class JetExpressionParsing extends AbstractJetParsing {
|
|||||||
private void parseValueArgument() {
|
private void parseValueArgument() {
|
||||||
PsiBuilder.Marker argument = mark();
|
PsiBuilder.Marker argument = mark();
|
||||||
if (at(IDENTIFIER) && lookahead(1) == EQ) {
|
if (at(IDENTIFIER) && lookahead(1) == EQ) {
|
||||||
|
PsiBuilder.Marker argName = mark();
|
||||||
|
PsiBuilder.Marker reference = mark();
|
||||||
advance(); // IDENTIFIER
|
advance(); // IDENTIFIER
|
||||||
|
reference.done(REFERENCE_EXPRESSION);
|
||||||
|
argName.done(VALUE_ARGUMENT_NAME);
|
||||||
advance(); // EQ
|
advance(); // EQ
|
||||||
}
|
}
|
||||||
if (at(OUT_KEYWORD) || at(REF_KEYWORD)) advance(); // REF or OUT
|
if (at(OUT_KEYWORD) || at(REF_KEYWORD)) advance(); // REF or OUT
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
package org.jetbrains.jet.lang.psi;
|
package org.jetbrains.jet.lang.psi;
|
||||||
|
|
||||||
import com.intellij.lang.ASTNode;
|
import com.intellij.lang.ASTNode;
|
||||||
import com.intellij.psi.PsiElement;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.jet.JetNodeTypes;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author max
|
* @author max
|
||||||
*/
|
*/
|
||||||
public class JetValueArgument extends JetElement implements ValueArgumentPsi {
|
public class JetValueArgument extends JetElement {
|
||||||
public JetValueArgument(@NotNull ASTNode node) {
|
public JetValueArgument(@NotNull ASTNode node) {
|
||||||
super(node);
|
super(node);
|
||||||
}
|
}
|
||||||
@@ -28,18 +28,9 @@ public class JetValueArgument extends JetElement implements ValueArgumentPsi {
|
|||||||
return findChildByClass(JetExpression.class);
|
return findChildByClass(JetExpression.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public PsiElement asElement() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public String getArgumentName() {
|
public JetValueArgumentName getArgumentName() {
|
||||||
ASTNode firstChildNode = getNode().getFirstChildNode();
|
return (JetValueArgumentName) findChildByType(JetNodeTypes.VALUE_ARGUMENT_NAME);
|
||||||
if (firstChildNode == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return firstChildNode.getElementType() == JetTokens.IDENTIFIER ? firstChildNode.getText() : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNamed() {
|
public boolean isNamed() {
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package org.jetbrains.jet.lang.psi;
|
||||||
|
|
||||||
|
import com.intellij.lang.ASTNode;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.jet.JetNodeTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
*/
|
||||||
|
public class JetValueArgumentName extends JetElement {
|
||||||
|
public JetValueArgumentName(@NotNull ASTNode node) {
|
||||||
|
super(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable @IfNotParsed
|
||||||
|
public JetSimpleNameExpression getReferenceExpression() {
|
||||||
|
return (JetSimpleNameExpression) findChildByType(JetNodeTypes.REFERENCE_EXPRESSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
package org.jetbrains.jet.lang.psi;
|
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author abreslav
|
|
||||||
*/
|
|
||||||
public interface ValueArgumentPsi {
|
|
||||||
|
|
||||||
class ArgumentExpressionWrapper implements ValueArgumentPsi {
|
|
||||||
|
|
||||||
private final JetExpression expression;
|
|
||||||
|
|
||||||
public ArgumentExpressionWrapper(JetExpression expression) {
|
|
||||||
this.expression = expression;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PsiElement asElement() {
|
|
||||||
return expression;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getArgumentName() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isNamed() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JetExpression getArgumentExpression() {
|
|
||||||
return expression;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PsiElement asElement();
|
|
||||||
@Nullable
|
|
||||||
String getArgumentName();
|
|
||||||
|
|
||||||
boolean isNamed();
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public JetExpression getArgumentExpression();
|
|
||||||
}
|
|
||||||
@@ -27,6 +27,7 @@ import org.jetbrains.jet.util.WritableSlice;
|
|||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
|
||||||
import static org.jetbrains.jet.lang.resolve.BindingContext.STATEMENT;
|
import static org.jetbrains.jet.lang.resolve.BindingContext.STATEMENT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -542,62 +543,240 @@ public class JetTypeInferrer {
|
|||||||
@NotNull JetCall call,
|
@NotNull JetCall call,
|
||||||
@NotNull JetType expectedType
|
@NotNull JetType expectedType
|
||||||
) {
|
) {
|
||||||
if (call.getTypeArguments().isEmpty()) {
|
JetExpression calleeExpression = call.getCalleeExpression();
|
||||||
JetExpression calleeExpression = call.getCalleeExpression();
|
Collection<FunctionDescriptor> candidates;
|
||||||
Collection<FunctionDescriptor> candidates;
|
JetReferenceExpression functionReference;
|
||||||
if (calleeExpression instanceof JetSimpleNameExpression) {
|
if (calleeExpression instanceof JetSimpleNameExpression) {
|
||||||
JetSimpleNameExpression expression = (JetSimpleNameExpression) calleeExpression;
|
JetSimpleNameExpression expression = (JetSimpleNameExpression) calleeExpression;
|
||||||
candidates = scope.getFunctionGroup(expression.getReferencedName()).getFunctionDescriptors();
|
functionReference = expression;
|
||||||
|
candidates = scope.getFunctionGroup(expression.getReferencedName()).getFunctionDescriptors();
|
||||||
|
}
|
||||||
|
else if (calleeExpression instanceof JetConstructorCalleeExpression) {
|
||||||
|
JetConstructorCalleeExpression expression = (JetConstructorCalleeExpression) calleeExpression;
|
||||||
|
functionReference = expression.getConstructorReferenceExpression();
|
||||||
|
JetType constructedType = typeResolver.resolveType(scope, expression.getTypeReference());
|
||||||
|
DeclarationDescriptor declarationDescriptor = constructedType.getConstructor().getDeclarationDescriptor();
|
||||||
|
if (declarationDescriptor instanceof ClassDescriptor) {
|
||||||
|
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
|
||||||
|
candidates = classDescriptor.getConstructors().getFunctionDescriptors();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new UnsupportedOperationException("Type argument inference not implemented");
|
trace.getErrorHandler().genericError(calleeExpression.getNode(), "Not a class");
|
||||||
}
|
|
||||||
|
|
||||||
assert candidates.size() == 1;
|
|
||||||
|
|
||||||
FunctionDescriptor candidate = candidates.iterator().next();
|
|
||||||
|
|
||||||
assert candidate.getTypeParameters().size() == call.getTypeArguments().size();
|
|
||||||
|
|
||||||
ConstraintSystem constraintSystem = new ConstraintSystem();
|
|
||||||
for (TypeParameterDescriptor typeParameterDescriptor : candidate.getTypeParameters()) {
|
|
||||||
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator<ValueParameterDescriptor> parameters = candidate.getValueParameters().iterator();
|
|
||||||
for (JetValueArgument valueArgument : call.getValueArguments()) {
|
|
||||||
assert !valueArgument.isNamed();
|
|
||||||
ValueParameterDescriptor valueParameterDescriptor = parameters.next();
|
|
||||||
JetExpression expression = valueArgument.getArgumentExpression();
|
|
||||||
JetType type = getType(scope, expression, false, NO_EXPECTED_TYPE);
|
|
||||||
constraintSystem.addSubtypingConstraint(type, valueParameterDescriptor.getOutType());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expectedType != NO_EXPECTED_TYPE) {
|
|
||||||
System.out.println("expectedType = " + expectedType);
|
|
||||||
constraintSystem.addSubtypingConstraint(candidate.getReturnType(), expectedType);
|
|
||||||
}
|
|
||||||
|
|
||||||
ConstraintSystem.Solution solution = constraintSystem.solve();
|
|
||||||
if (!solution.isSuccessful()) {
|
|
||||||
trace.getErrorHandler().genericError(calleeExpression.getNode(), "Type inference failed");
|
|
||||||
// for (Inconsistency inconsistency : solution.getInconsistencies()) {
|
|
||||||
// System.out.println("inconsistency = " + inconsistency);
|
|
||||||
// }
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
for (TypeParameterDescriptor typeParameterDescriptor : candidate.getTypeParameters()) {
|
|
||||||
JetType value = solution.getValue(typeParameterDescriptor);
|
|
||||||
System.out.println("typeParameterDescriptor = " + typeParameterDescriptor);
|
|
||||||
System.out.println("value = " + value);
|
|
||||||
}
|
|
||||||
return solution.getSubstitutor().substitute(candidate.getReturnType(), Variance.INVARIANT); // TODO
|
|
||||||
}
|
|
||||||
// return null;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new UnsupportedOperationException("Explicit type arguments not implemented");
|
throw new UnsupportedOperationException("Type argument inference not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<FunctionDescriptor, FunctionDescriptor> successfulCandidates = Maps.newHashMap();
|
||||||
|
Set<FunctionDescriptor> failedCandidates = Sets.newHashSet();
|
||||||
|
Map<FunctionDescriptor, ConstraintSystem.Solution> solutions = Maps.newHashMap();
|
||||||
|
Map<FunctionDescriptor, TemporaryBindingTrace> traces = Maps.newHashMap();
|
||||||
|
|
||||||
|
for (FunctionDescriptor candidate : candidates) {
|
||||||
|
TemporaryBindingTrace temporaryTrace = new TemporaryBindingTrace(trace.getBindingContext());
|
||||||
|
traces.put(candidate, temporaryTrace);
|
||||||
|
Services temporaryServices = getServices(temporaryTrace);
|
||||||
|
|
||||||
|
temporaryTrace.record(BindingContext.REFERENCE_TARGET, functionReference, candidate);
|
||||||
|
|
||||||
|
// Argument to parameter matching
|
||||||
|
Map<JetValueArgument, ValueParameterDescriptor> argumentsToParameters = Maps.newHashMap();
|
||||||
|
Set<ValueParameterDescriptor> usedParameters = Sets.newHashSet();
|
||||||
|
|
||||||
|
List<ValueParameterDescriptor> valueParameters = candidate.getValueParameters();
|
||||||
|
Map<String, ValueParameterDescriptor> parameterByName = Maps.newHashMap();
|
||||||
|
for (ValueParameterDescriptor valueParameter : valueParameters) {
|
||||||
|
parameterByName.put(valueParameter.getName(), valueParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<JetValueArgument> valueArguments = call.getValueArguments();
|
||||||
|
boolean someNamed = false;
|
||||||
|
boolean somePositioned = false;
|
||||||
|
boolean error = false;
|
||||||
|
for (int i = 0; i < valueArguments.size(); i++) {
|
||||||
|
JetValueArgument valueArgument = valueArguments.get(i);
|
||||||
|
if (valueArgument.isNamed()) {
|
||||||
|
someNamed = true;
|
||||||
|
if (somePositioned) {
|
||||||
|
temporaryTrace.getErrorHandler().genericError(valueArgument.getArgumentName().getNode(), "Mixing named and positioned arguments in not allowed");
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ValueParameterDescriptor valueParameterDescriptor = parameterByName.get(valueArgument.getArgumentName().getName());
|
||||||
|
usedParameters.add(valueParameterDescriptor);
|
||||||
|
if (valueParameterDescriptor == null) {
|
||||||
|
temporaryTrace.getErrorHandler().genericError(valueArgument.getArgumentName().getNode(), "Cannot find a parameter with this name");
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
trace.record(REFERENCE_TARGET, valueArgument.getArgumentName().getReferenceExpression(), valueParameterDescriptor);
|
||||||
|
argumentsToParameters.put(valueArgument, valueParameterDescriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
somePositioned = true;
|
||||||
|
if (someNamed) {
|
||||||
|
temporaryTrace.getErrorHandler().genericError(valueArgument.getNode(), "Mixing named and positioned arguments in not allowed");
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (i < valueParameters.size()) {
|
||||||
|
ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(i);
|
||||||
|
usedParameters.add(valueParameterDescriptor);
|
||||||
|
argumentsToParameters.put(valueArgument, valueParameterDescriptor);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1);
|
||||||
|
if (valueParameterDescriptor.isVararg()) {
|
||||||
|
argumentsToParameters.put(valueArgument, valueParameterDescriptor);
|
||||||
|
usedParameters.add(valueParameterDescriptor);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
trace.getErrorHandler().genericError(valueArgument.getNode(), "Too many arguments");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ValueParameterDescriptor valueParameter : valueParameters) {
|
||||||
|
if (!usedParameters.contains(valueParameter)) {
|
||||||
|
if (!valueParameter.hasDefaultValue()) {
|
||||||
|
trace.getErrorHandler().genericError(call.getValueArgumentList().getNode(), "No value passed for parameter " + valueParameter.getName());
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) continue;
|
||||||
|
|
||||||
|
if (call.getTypeArguments().isEmpty()) {
|
||||||
|
// Type argument inference
|
||||||
|
|
||||||
|
ConstraintSystem constraintSystem = new ConstraintSystem();
|
||||||
|
for (TypeParameterDescriptor typeParameterDescriptor : candidate.getTypeParameters()) {
|
||||||
|
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<JetValueArgument, ValueParameterDescriptor> entry : argumentsToParameters.entrySet()) {
|
||||||
|
JetValueArgument valueArgument = entry.getKey();
|
||||||
|
ValueParameterDescriptor valueParameterDescriptor = entry.getValue();
|
||||||
|
|
||||||
|
JetExpression expression = valueArgument.getArgumentExpression();
|
||||||
|
// TODO : more attempts, with different expected types
|
||||||
|
JetType type = temporaryServices.getType(scope, expression, false, NO_EXPECTED_TYPE);
|
||||||
|
constraintSystem.addSubtypingConstraint(type, valueParameterDescriptor.getOutType());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expectedType != NO_EXPECTED_TYPE) {
|
||||||
|
constraintSystem.addSubtypingConstraint(candidate.getReturnType(), expectedType);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstraintSystem.Solution solution = constraintSystem.solve();
|
||||||
|
solutions.put(candidate, solution);
|
||||||
|
if (solution.isSuccessful()) {
|
||||||
|
successfulCandidates.put(candidate, candidate.substitute(solution.getSubstitutor()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
temporaryTrace.getErrorHandler().genericError(calleeExpression.getNode(), "Type inference failed");
|
||||||
|
failedCandidates.add(candidate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final List<JetTypeProjection> jetTypeArguments = call.getTypeArguments();
|
||||||
|
|
||||||
|
for (JetTypeProjection typeArgument : jetTypeArguments) {
|
||||||
|
if (typeArgument.getProjectionKind() != JetProjectionKind.NONE) {
|
||||||
|
trace.getErrorHandler().genericError(typeArgument.getNode(), "Projections are not allowed on type parameters for methods"); // TODO : better positioning
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<JetType> typeArguments = new ArrayList<JetType>();
|
||||||
|
for (JetTypeProjection projection : jetTypeArguments) {
|
||||||
|
// TODO : check that there's no projection
|
||||||
|
JetTypeReference typeReference = projection.getTypeReference();
|
||||||
|
if (typeReference != null) {
|
||||||
|
typeArguments.add(new TypeResolver(semanticServices, temporaryTrace, true).resolveType(scope, typeReference));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int typeArgCount = typeArguments.size();
|
||||||
|
if (candidate.getTypeParameters().size() == typeArgCount) {
|
||||||
|
FunctionDescriptor substitutedFunctionDescriptor = FunctionDescriptorUtil.substituteFunctionDescriptor(typeArguments, candidate);
|
||||||
|
|
||||||
|
assert substitutedFunctionDescriptor != null;
|
||||||
|
Map<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap = Maps.newHashMap();
|
||||||
|
for (ValueParameterDescriptor valueParameterDescriptor : substitutedFunctionDescriptor.getValueParameters()) {
|
||||||
|
parameterMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean localError = false;
|
||||||
|
for (Map.Entry<JetValueArgument, ValueParameterDescriptor> entry : argumentsToParameters.entrySet()) {
|
||||||
|
JetValueArgument valueArgument = entry.getKey();
|
||||||
|
ValueParameterDescriptor valueParameterDescriptor = entry.getValue();
|
||||||
|
|
||||||
|
ValueParameterDescriptor substitutedParameter = parameterMap.get(valueParameterDescriptor.getOriginal());
|
||||||
|
|
||||||
|
JetType parameterType = substitutedParameter.getOutType();
|
||||||
|
JetType type = temporaryServices.getType(scope, valueArgument.getArgumentExpression(), false, parameterType);
|
||||||
|
if (type == null) {
|
||||||
|
localError = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (localError) {
|
||||||
|
failedCandidates.add(candidate);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
successfulCandidates.put(candidate, substitutedFunctionDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
failedCandidates.add(candidate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (successfulCandidates.size() > 0) {
|
||||||
|
if (successfulCandidates.size() == 1) {
|
||||||
|
Map.Entry<FunctionDescriptor, FunctionDescriptor> entry = successfulCandidates.entrySet().iterator().next();
|
||||||
|
FunctionDescriptor functionDescriptor = entry.getKey();
|
||||||
|
FunctionDescriptor result = entry.getValue();
|
||||||
|
|
||||||
|
TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor);
|
||||||
|
temporaryTrace.addAllMyDataTo(trace);
|
||||||
|
return result.getReturnType();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// TODO : Choose more specific
|
||||||
|
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
for (FunctionDescriptor functionDescriptor : successfulCandidates.keySet()) {
|
||||||
|
stringBuilder.append(DescriptorRenderer.HTML.render(functionDescriptor)).append("<br/>");
|
||||||
|
}
|
||||||
|
|
||||||
|
trace.getErrorHandler().genericError(calleeExpression.getNode(), "Overload resolution ambiguity: <br/>" + stringBuilder);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (failedCandidates.size() == 1) {
|
||||||
|
FunctionDescriptor functionDescriptor = failedCandidates.iterator().next();
|
||||||
|
TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor);
|
||||||
|
temporaryTrace.addAllMyDataTo(trace);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
for (FunctionDescriptor functionDescriptor : failedCandidates) {
|
||||||
|
stringBuilder.append(DescriptorRenderer.HTML.render(functionDescriptor)).append("<br/>");
|
||||||
|
}
|
||||||
|
|
||||||
|
trace.getErrorHandler().genericError(calleeExpression.getNode(), "None of the following functions can be called with the arguments supplied: <br/>" + stringBuilder);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user