Detailed status for ValueArgumentsToParameterMapper

When a non-vararg parameter gets spread with a '*' in front of it, a "weak error" is returned.
A candidate with a weak error in parameter matching is type-checked, but not successful.
This commit is contained in:
Andrey Breslav
2012-04-20 18:47:36 +04:00
parent 09f7c012bd
commit da474b961f
3 changed files with 60 additions and 25 deletions
@@ -49,7 +49,7 @@ public enum ResolutionStatus {
} }
public ResolutionStatus combine(ResolutionStatus other) { public ResolutionStatus combine(ResolutionStatus other) {
if (this.isSuccess()) return other; if (this == UNKNOWN_STATUS || this.isSuccess()) return other;
if (!other.isSuccess() && this.getSeverityIndex() < other.getSeverityIndex()) return other; if (!other.isSuccess() && this.getSeverityIndex() < other.getSeverityIndex()) return other;
return this; return this;
} }
@@ -81,8 +81,8 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements ResolvedC
return status; return status;
} }
public void setStatus(@NotNull ResolutionStatus status) { public void addStatus(@NotNull ResolutionStatus status) {
this.status = status; this.status = this.status.combine(status);
} }
@NotNull @NotNull
@@ -33,17 +33,49 @@ import java.util.Set;
import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
import static org.jetbrains.jet.lang.resolve.calls.ValueArgumentsToParametersMapper.Status.ERROR;
import static org.jetbrains.jet.lang.resolve.calls.ValueArgumentsToParametersMapper.Status.OK;
import static org.jetbrains.jet.lang.resolve.calls.ValueArgumentsToParametersMapper.Status.WEAK_ERROR;
/** /**
* @author abreslav * @author abreslav
*/ */
/*package*/ class ValueArgumentsToParametersMapper { /*package*/ class ValueArgumentsToParametersMapper {
public static <D extends CallableDescriptor> boolean mapValueArgumentsToParameters(
public enum Status {
ERROR(false),
WEAK_ERROR(false),
OK(true);
private final boolean success;
private Status(boolean success) {
this.success = success;
}
public boolean isSuccess() {
return success;
}
public Status compose(Status other) {
switch (other) {
case ERROR:
return ERROR;
case WEAK_ERROR:
if (this != ERROR) {
return WEAK_ERROR;
}
default:
return this;
}
}
}
public static <D extends CallableDescriptor> Status mapValueArgumentsToParameters(
@NotNull Call call, @NotNull Call call,
@NotNull TracingStrategy tracing, @NotNull TracingStrategy tracing,
@NotNull ResolvedCallImpl<D> candidateCall @NotNull ResolvedCallImpl<D> candidateCall
) { ) {
TemporaryBindingTrace temporaryTrace = candidateCall.getTrace(); TemporaryBindingTrace temporaryTrace = candidateCall.getTrace();
Map<ValueParameterDescriptor, VarargValueArgument> varargs = Maps.newHashMap(); Map<ValueParameterDescriptor, VarargValueArgument> varargs = Maps.newHashMap();
Set<ValueParameterDescriptor> usedParameters = Sets.newHashSet(); Set<ValueParameterDescriptor> usedParameters = Sets.newHashSet();
@@ -61,7 +93,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
List<? extends ValueArgument> valueArguments = call.getValueArguments(); List<? extends ValueArgument> valueArguments = call.getValueArguments();
boolean error = false; Status status = OK;
boolean someNamed = false; boolean someNamed = false;
boolean somePositioned = false; boolean somePositioned = false;
for (int i = 0; i < valueArguments.size(); i++) { for (int i = 0; i < valueArguments.size(); i++) {
@@ -72,47 +104,47 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
ValueParameterDescriptor valueParameterDescriptor = parameterByName.get(nameReference.getReferencedName()); ValueParameterDescriptor valueParameterDescriptor = parameterByName.get(nameReference.getReferencedName());
if (valueParameterDescriptor == null) { if (valueParameterDescriptor == null) {
temporaryTrace.report(NAMED_PARAMETER_NOT_FOUND.on(nameReference)); temporaryTrace.report(NAMED_PARAMETER_NOT_FOUND.on(nameReference));
error = true; status = ERROR;
} }
else { else {
if (!usedParameters.add(valueParameterDescriptor)) { if (!usedParameters.add(valueParameterDescriptor)) {
temporaryTrace.report(ARGUMENT_PASSED_TWICE.on(nameReference)); temporaryTrace.report(ARGUMENT_PASSED_TWICE.on(nameReference));
} }
temporaryTrace.record(REFERENCE_TARGET, nameReference, valueParameterDescriptor); temporaryTrace.record(REFERENCE_TARGET, nameReference, valueParameterDescriptor);
put(candidateCall, valueParameterDescriptor, valueArgument, varargs); status = status.compose(put(candidateCall, valueParameterDescriptor, valueArgument, varargs));
} }
if (somePositioned) { if (somePositioned) {
temporaryTrace.report(MIXING_NAMED_AND_POSITIONED_ARGUMENTS.on(nameReference)); temporaryTrace.report(MIXING_NAMED_AND_POSITIONED_ARGUMENTS.on(nameReference));
error = true; status = ERROR;
} }
} }
else { else {
somePositioned = true; somePositioned = true;
if (someNamed) { if (someNamed) {
temporaryTrace.report(MIXING_NAMED_AND_POSITIONED_ARGUMENTS.on(valueArgument.asElement())); temporaryTrace.report(MIXING_NAMED_AND_POSITIONED_ARGUMENTS.on(valueArgument.asElement()));
error = true; status = ERROR;
} }
else { else {
int parameterCount = valueParameters.size(); int parameterCount = valueParameters.size();
if (i < parameterCount) { if (i < parameterCount) {
ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(i); ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(i);
usedParameters.add(valueParameterDescriptor); usedParameters.add(valueParameterDescriptor);
put(candidateCall, valueParameterDescriptor, valueArgument, varargs); status = status.compose(put(candidateCall, valueParameterDescriptor, valueArgument, varargs));
} }
else if (!valueParameters.isEmpty()) { else if (!valueParameters.isEmpty()) {
ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1); ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1);
if (valueParameterDescriptor.getVarargElementType() != null) { if (valueParameterDescriptor.getVarargElementType() != null) {
put(candidateCall, valueParameterDescriptor, valueArgument, varargs); status = status.compose(put(candidateCall, valueParameterDescriptor, valueArgument, varargs));
usedParameters.add(valueParameterDescriptor); usedParameters.add(valueParameterDescriptor);
} }
else { else {
temporaryTrace.report(TOO_MANY_ARGUMENTS.on(valueArgument.asElement(), candidate)); temporaryTrace.report(TOO_MANY_ARGUMENTS.on(valueArgument.asElement(), candidate));
error = true; status = ERROR;
} }
} }
else { else {
temporaryTrace.report(TOO_MANY_ARGUMENTS.on(valueArgument.asElement(), candidate)); temporaryTrace.report(TOO_MANY_ARGUMENTS.on(valueArgument.asElement(), candidate));
error = true; status = ERROR;
} }
} }
} }
@@ -124,7 +156,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
if (valueParameters.isEmpty()) { if (valueParameters.isEmpty()) {
temporaryTrace.report(TOO_MANY_ARGUMENTS.on(possiblyLabeledFunctionLiteral, candidate)); temporaryTrace.report(TOO_MANY_ARGUMENTS.on(possiblyLabeledFunctionLiteral, candidate));
error = true; status = ERROR;
} }
else { else {
JetFunctionLiteralExpression functionLiteral; JetFunctionLiteralExpression functionLiteral;
@@ -139,15 +171,15 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1); ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1);
if (valueParameterDescriptor.getVarargElementType() != null) { if (valueParameterDescriptor.getVarargElementType() != null) {
temporaryTrace.report(VARARG_OUTSIDE_PARENTHESES.on(possiblyLabeledFunctionLiteral)); temporaryTrace.report(VARARG_OUTSIDE_PARENTHESES.on(possiblyLabeledFunctionLiteral));
error = true; status = ERROR;
} }
else { else {
if (!usedParameters.add(valueParameterDescriptor)) { if (!usedParameters.add(valueParameterDescriptor)) {
temporaryTrace.report(TOO_MANY_ARGUMENTS.on(possiblyLabeledFunctionLiteral, candidate)); temporaryTrace.report(TOO_MANY_ARGUMENTS.on(possiblyLabeledFunctionLiteral, candidate));
error = true; status = ERROR;
} }
else { else {
put(candidateCall, valueParameterDescriptor, CallMaker.makeValueArgument(functionLiteral), varargs); status = status.compose(put(candidateCall, valueParameterDescriptor, CallMaker.makeValueArgument(functionLiteral), varargs));
} }
} }
} }
@@ -155,7 +187,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
for (int i = 1; i < functionLiteralArguments.size(); i++) { for (int i = 1; i < functionLiteralArguments.size(); i++) {
JetExpression argument = functionLiteralArguments.get(i); JetExpression argument = functionLiteralArguments.get(i);
temporaryTrace.report(MANY_FUNCTION_LITERAL_ARGUMENTS.on(argument)); temporaryTrace.report(MANY_FUNCTION_LITERAL_ARGUMENTS.on(argument));
error = true; status = ERROR;
} }
} }
@@ -171,7 +203,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
else { else {
// tracing.reportWrongValueArguments(temporaryTrace, "No value passed for parameter " + valueParameter.getName()); // tracing.reportWrongValueArguments(temporaryTrace, "No value passed for parameter " + valueParameter.getName());
tracing.noValueForParameter(temporaryTrace, valueParameter); tracing.noValueForParameter(temporaryTrace, valueParameter);
error = true; status = ERROR;
} }
} }
} }
@@ -180,21 +212,22 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
ReceiverDescriptor receiverArgument = candidateCall.getReceiverArgument(); ReceiverDescriptor receiverArgument = candidateCall.getReceiverArgument();
if (receiverParameter.exists() &&!receiverArgument.exists()) { if (receiverParameter.exists() &&!receiverArgument.exists()) {
tracing.missingReceiver(temporaryTrace, receiverParameter); tracing.missingReceiver(temporaryTrace, receiverParameter);
error = true; status = ERROR;
} }
if (!receiverParameter.exists() && receiverArgument.exists()) { if (!receiverParameter.exists() && receiverArgument.exists()) {
tracing.noReceiverAllowed(temporaryTrace); tracing.noReceiverAllowed(temporaryTrace);
error = true; status = ERROR;
} }
if (candidateCall.getThisObject().exists() != candidateCall.getResultingDescriptor().getExpectedThisObject().exists()) { if (candidateCall.getThisObject().exists() != candidateCall.getResultingDescriptor().getExpectedThisObject().exists()) {
assert false : "Shouldn't happen because of TaskPrioritizer: " + candidateCall.getCandidateDescriptor(); assert false : "Shouldn't happen because of TaskPrioritizer: " + candidateCall.getCandidateDescriptor();
} }
return error; return status;
} }
private static <D extends CallableDescriptor> void put(ResolvedCallImpl<D> candidateCall, ValueParameterDescriptor valueParameterDescriptor, ValueArgument valueArgument, Map<ValueParameterDescriptor, VarargValueArgument> varargs) { private static <D extends CallableDescriptor> Status put(ResolvedCallImpl<D> candidateCall, ValueParameterDescriptor valueParameterDescriptor, ValueArgument valueArgument, Map<ValueParameterDescriptor, VarargValueArgument> varargs) {
Status error = OK;
if (valueParameterDescriptor.getVarargElementType() != null) { if (valueParameterDescriptor.getVarargElementType() != null) {
VarargValueArgument vararg = varargs.get(valueParameterDescriptor); VarargValueArgument vararg = varargs.get(valueParameterDescriptor);
if (vararg == null) { if (vararg == null) {
@@ -207,11 +240,13 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
else { else {
LeafPsiElement spread = valueArgument.getSpreadElement(); LeafPsiElement spread = valueArgument.getSpreadElement();
if (spread != null) { if (spread != null) {
candidateCall.getTrace().report(NON_VARARG_SPREAD.on(spread)); candidateCall.getTrace().report(NON_VARARG_SPREAD.on(spread));
error = WEAK_ERROR;
} }
ResolvedValueArgument argument = new ExpressionValueArgument(valueArgument); ResolvedValueArgument argument = new ExpressionValueArgument(valueArgument);
candidateCall.recordValueArgument(valueParameterDescriptor, argument); candidateCall.recordValueArgument(valueParameterDescriptor, argument);
} }
return error;
} }
/** /**