store constraint system without expected type constraint

for easier 'type inference expected type mismatch' reporting
This commit is contained in:
Svetlana Isakova
2013-03-06 15:55:48 +04:00
parent 54cd8c82a3
commit 4d4fd5885d
7 changed files with 59 additions and 47 deletions
@@ -30,7 +30,6 @@ import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults; import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl; import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl;
import org.jetbrains.jet.lang.resolve.calls.util.CallMaker; import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
@@ -166,7 +165,7 @@ public class CallExpressionResolver {
// Expected type mismatch was reported before as 'TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH' // Expected type mismatch was reported before as 'TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH'
ConstraintSystem constraintSystem = callToComplete.getConstraintSystem(); ConstraintSystem constraintSystem = callToComplete.getConstraintSystem();
if (constraintSystem != null && constraintSystem.hasExpectedTypeMismatch()) return null; if (constraintSystem != null && constraintSystem.hasOnlyExpectedTypeMismatch()) return null;
} }
return results.isSingleResult() ? results.getResultingCall() : null; return results.isSingleResult() ? results.getResultingCall() : null;
@@ -225,13 +225,10 @@ public class CandidateResolver {
ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem(); ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
assert constraintSystem != null; assert constraintSystem != null;
ConstraintSystem constraintSystemWithoutExpectedTypeConstraint = constraintSystem.copy(); constraintSystem.addSupertypeConstraint(context.expectedType, descriptor.getReturnType(), ConstraintPosition.EXPECTED_TYPE_POSITION);
constraintSystem.addSupertypeConstraint(context.expectedType, descriptor.getReturnType(),
ConstraintPosition.EXPECTED_TYPE_POSITION);
if (!constraintSystem.isSuccessful()) { if (!constraintSystem.isSuccessful()) {
resolvedCall.setResultingSubstitutor(constraintSystemWithoutExpectedTypeConstraint.getResultingSubstitutor()); resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
completeNestedCallsInference(context); completeNestedCallsInference(context);
List<JetType> argumentTypes = checkValueArgumentTypes(context, resolvedCall, context.trace, List<JetType> argumentTypes = checkValueArgumentTypes(context, resolvedCall, context.trace,
RESOLVE_FUNCTION_ARGUMENTS).argumentTypes; RESOLVE_FUNCTION_ARGUMENTS).argumentTypes;
@@ -239,7 +236,7 @@ public class CandidateResolver {
InferenceErrorData.ExtendedInferenceErrorData errorData = InferenceErrorData InferenceErrorData.ExtendedInferenceErrorData errorData = InferenceErrorData
.create(descriptor, constraintSystem, argumentTypes, receiverType, context.expectedType); .create(descriptor, constraintSystem, argumentTypes, receiverType, context.expectedType);
context.tracing.typeInferenceFailed(context.trace, errorData, constraintSystemWithoutExpectedTypeConstraint); context.tracing.typeInferenceFailed(context.trace, errorData);
resolvedCall.addStatus(ResolutionStatus.OTHER_ERROR); resolvedCall.addStatus(ResolutionStatus.OTHER_ERROR);
return; return;
} }
@@ -104,7 +104,7 @@ public interface ConstraintSystem {
/** /**
* Returns <tt>true</tt> if there is type constructor mismatch only in {@link ConstraintPosition.EXPECTED_TYPE_POSITION}. * Returns <tt>true</tt> if there is type constructor mismatch only in {@link ConstraintPosition.EXPECTED_TYPE_POSITION}.
*/ */
boolean hasExpectedTypeMismatch(); boolean hasOnlyExpectedTypeMismatch();
/** /**
* Returns <tt>true</tt> if there is an error in constraining types. <p/> * Returns <tt>true</tt> if there is an error in constraining types. <p/>
@@ -125,6 +125,8 @@ public interface ConstraintSystem {
* - type constraints <p/> * - type constraints <p/>
* - variance of the type variable // not implemented yet <p/> * - variance of the type variable // not implemented yet <p/>
* - type parameter bounds (that can bind type variables with each other). // not implemented yet * - type parameter bounds (that can bind type variables with each other). // not implemented yet
* If the addition of the 'expected type' constraint made the system fail,
* this constraint is not included in the resulting substitution.
*/ */
@NotNull @NotNull
TypeSubstitutor getResultingSubstitutor(); TypeSubstitutor getResultingSubstitutor();
@@ -31,7 +31,6 @@ import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure;
import org.jetbrains.jet.lang.types.checker.TypingConstraints; import org.jetbrains.jet.lang.types.checker.TypingConstraints;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -53,7 +52,9 @@ public class ConstraintSystemImpl implements ConstraintSystem {
private final TypeSubstitutor resultingSubstitutor; private final TypeSubstitutor resultingSubstitutor;
private final TypeSubstitutor currentSubstitutor; private final TypeSubstitutor currentSubstitutor;
private boolean hasErrorInConstrainingTypes; private boolean hasErrorInConstrainingTypes;
private boolean hasExpectedTypeMismatch;
@Nullable
private ConstraintSystem systemWithoutExpectedTypeConstraint;
public ConstraintSystemImpl() { public ConstraintSystemImpl() {
this.resultingSubstitutor = createTypeSubstitutorWithDefaultForUnknownTypeParameter(new TypeProjection(CANT_INFER_TYPE_PARAMETER)); this.resultingSubstitutor = createTypeSubstitutorWithDefaultForUnknownTypeParameter(new TypeProjection(CANT_INFER_TYPE_PARAMETER));
@@ -102,13 +103,20 @@ public class ConstraintSystemImpl implements ConstraintSystem {
} }
@Override @Override
public boolean hasExpectedTypeMismatch() { public boolean hasOnlyExpectedTypeMismatch() {
return hasExpectedTypeMismatch if (systemWithoutExpectedTypeConstraint == null) {
|| (errorConstraintPositions.size() == 1 && errorConstraintPositions.contains(ConstraintPosition.EXPECTED_TYPE_POSITION)); // the expected type constraint isn't added, there can't be an error with it
} return false;
}
public void setHasExpectedTypeMismatch() { if (!isSuccessful() && systemWithoutExpectedTypeConstraint.isSuccessful()) {
hasExpectedTypeMismatch = true; return true;
}
if (errorConstraintPositions.size() == 1 && errorConstraintPositions.contains(ConstraintPosition.EXPECTED_TYPE_POSITION)) {
// if systemWithoutExpectedTypeConstraint has unknown type parameters, it's not successful,
// but there can be expected type mismatch after expected type is added
return true;
}
return false;
} }
@Override @Override
@@ -157,6 +165,11 @@ public class ConstraintSystemImpl implements ConstraintSystem {
@NotNull JetType subjectType, @NotNull JetType subjectType,
@NotNull ConstraintPosition constraintPosition @NotNull ConstraintPosition constraintPosition
) { ) {
if (constrainingType == TypeUtils.NO_EXPECTED_TYPE) return;
if (constraintPosition == ConstraintPosition.EXPECTED_TYPE_POSITION) {
systemWithoutExpectedTypeConstraint = copy();
}
addConstraint(SUB_TYPE, subjectType, constrainingType, constraintPosition); addConstraint(SUB_TYPE, subjectType, constrainingType, constraintPosition);
} }
@@ -212,9 +225,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
} }
private boolean isErrorOrSpecialType(@Nullable JetType type) { private boolean isErrorOrSpecialType(@Nullable JetType type) {
if (type == TypeUtils.NO_EXPECTED_TYPE if (type == DONT_CARE || type == CANT_INFER_TYPE_PARAMETER) {
|| type == DONT_CARE
|| type == CANT_INFER_TYPE_PARAMETER) {
return true; return true;
} }
@@ -365,6 +376,10 @@ public class ConstraintSystemImpl implements ConstraintSystem {
@NotNull @NotNull
@Override @Override
public TypeSubstitutor getResultingSubstitutor() { public TypeSubstitutor getResultingSubstitutor() {
if (hasOnlyExpectedTypeMismatch()) {
assert systemWithoutExpectedTypeConstraint != null;
return systemWithoutExpectedTypeConstraint.getResultingSubstitutor();
}
return resultingSubstitutor; return resultingSubstitutor;
} }
@@ -25,7 +25,9 @@ import org.jetbrains.jet.lang.types.TypeUtils;
import java.util.List; import java.util.List;
public class InferenceErrorData { public class InferenceErrorData {
@NotNull
public final CallableDescriptor descriptor; public final CallableDescriptor descriptor;
@NotNull
public final ConstraintSystem constraintSystem; public final ConstraintSystem constraintSystem;
private InferenceErrorData(@NotNull CallableDescriptor descriptor, @NotNull ConstraintSystem constraintSystem) { private InferenceErrorData(@NotNull CallableDescriptor descriptor, @NotNull ConstraintSystem constraintSystem) {
@@ -34,14 +36,16 @@ public class InferenceErrorData {
} }
public static class ExtendedInferenceErrorData extends InferenceErrorData { public static class ExtendedInferenceErrorData extends InferenceErrorData {
@Nullable
public final JetType receiverArgumentType; public final JetType receiverArgumentType;
@NotNull
public final JetType expectedType; public final JetType expectedType;
@NotNull
public final List<JetType> valueArgumentsTypes; public final List<JetType> valueArgumentsTypes;
private ExtendedInferenceErrorData( private ExtendedInferenceErrorData(
@NotNull CallableDescriptor descriptor, @NotNull ConstraintSystem constraintSystem, @NotNull CallableDescriptor descriptor, @NotNull ConstraintSystem constraintSystem,
@NotNull List<JetType> valueArgumentsTypes, @Nullable JetType receiverArgumentType, @Nullable JetType expectedType @NotNull List<JetType> valueArgumentsTypes, @Nullable JetType receiverArgumentType, @NotNull JetType expectedType
) { ) {
super(descriptor, constraintSystem); super(descriptor, constraintSystem);
this.receiverArgumentType = receiverArgumentType; this.receiverArgumentType = receiverArgumentType;
@@ -51,9 +55,8 @@ public class InferenceErrorData {
} }
public static ExtendedInferenceErrorData create(@NotNull CallableDescriptor descriptor, @NotNull ConstraintSystem constraintSystem, public static ExtendedInferenceErrorData create(@NotNull CallableDescriptor descriptor, @NotNull ConstraintSystem constraintSystem,
@NotNull List<JetType> valueArgumentsTypes, @Nullable JetType receiverArgumentType, @Nullable JetType expectedType) { @NotNull List<JetType> valueArgumentsTypes, @Nullable JetType receiverArgumentType, @NotNull JetType expectedType) {
return new ExtendedInferenceErrorData(descriptor, constraintSystem, valueArgumentsTypes, receiverArgumentType, return new ExtendedInferenceErrorData(descriptor, constraintSystem, valueArgumentsTypes, receiverArgumentType, expectedType);
expectedType != TypeUtils.NO_EXPECTED_TYPE ? expectedType : null);
} }
public static InferenceErrorData create(@NotNull CallableDescriptor descriptor, @NotNull ConstraintSystem constraintSystem) { public static InferenceErrorData create(@NotNull CallableDescriptor descriptor, @NotNull ConstraintSystem constraintSystem) {
@@ -92,8 +92,7 @@ public interface TracingStrategy {
public void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor) {} public void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor) {}
@Override @Override
public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull ExtendedInferenceErrorData inferenceErrorData, public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull ExtendedInferenceErrorData inferenceErrorData) {}
@NotNull ConstraintSystem systemWithoutExpectedTypeConstraint) {}
@Override @Override
public void upperBoundViolated(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData) {} public void upperBoundViolated(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData) {}
@@ -136,8 +135,7 @@ public interface TracingStrategy {
void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor); void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor);
void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull ExtendedInferenceErrorData inferenceErrorData, void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull ExtendedInferenceErrorData inferenceErrorData);
@NotNull ConstraintSystem systemWithoutExpectedTypeConstraint);
void upperBoundViolated(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData); void upperBoundViolated(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData);
} }
@@ -25,7 +25,6 @@ import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem; import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl;
import org.jetbrains.jet.lang.resolve.calls.inference.InferenceErrorData; import org.jetbrains.jet.lang.resolve.calls.inference.InferenceErrorData;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall; import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
@@ -34,6 +33,7 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.jet.lang.types.ErrorUtils; import org.jetbrains.jet.lang.types.ErrorUtils;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.lang.types.Variance; import org.jetbrains.jet.lang.types.Variance;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions; import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
import org.jetbrains.jet.lexer.JetToken; import org.jetbrains.jet.lexer.JetToken;
@@ -206,26 +206,24 @@ public class TracingStrategyImpl implements TracingStrategy {
} }
@Override @Override
public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData.ExtendedInferenceErrorData data, @NotNull ConstraintSystem systemWithoutExpectedTypeConstraint) { public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData.ExtendedInferenceErrorData data) {
ConstraintSystem constraintSystem = data.constraintSystem; ConstraintSystem constraintSystem = data.constraintSystem;
assert !constraintSystem.isSuccessful(); assert !constraintSystem.isSuccessful() : "Report error only for not successful constraint system";
if (constraintSystem.hasErrorInConstrainingTypes()) { if (constraintSystem.hasErrorInConstrainingTypes()) {
// Do not report type inference errors if there is one in the arguments
// (it's useful, when the arguments, e.g. lambdas or calls are incomplete)
return; return;
} }
boolean successfulWithoutExpectedTypeConstraint = systemWithoutExpectedTypeConstraint.isSuccessful(); if (constraintSystem.hasOnlyExpectedTypeMismatch()) {
if (constraintSystem.hasExpectedTypeMismatch() || successfulWithoutExpectedTypeConstraint) { JetType declaredReturnType = data.descriptor.getReturnType();
JetType returnType = data.descriptor.getReturnType(); if (declaredReturnType == null) return;
assert returnType != null;
if (successfulWithoutExpectedTypeConstraint) { JetType substitutedReturnType = constraintSystem.getResultingSubstitutor().substitute(declaredReturnType, Variance.INVARIANT);
returnType = systemWithoutExpectedTypeConstraint.getResultingSubstitutor().substitute(returnType, Variance.INVARIANT); assert substitutedReturnType != null; //todo
assert returnType != null;
} assert data.expectedType != TypeUtils.NO_EXPECTED_TYPE : "Expected type doesn't exist, but there is an expected type mismatch error";
assert data.expectedType != null; trace.report(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.on(reference, substitutedReturnType, data.expectedType));
trace.report(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.on(reference, returnType, data.expectedType));
//todo[ConstraintSystemImpl]
if (constraintSystem instanceof ConstraintSystemImpl) {
((ConstraintSystemImpl) constraintSystem).setHasExpectedTypeMismatch();
}
} }
else if (constraintSystem.hasTypeConstructorMismatch()) { else if (constraintSystem.hasTypeConstructorMismatch()) {
trace.report(TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH.on(reference, data)); trace.report(TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH.on(reference, data));