extracted ConstraintSystemStatus

This commit is contained in:
Svetlana Isakova
2013-09-17 15:22:09 +04:00
parent 4e45b91f07
commit eb513438c9
11 changed files with 180 additions and 137 deletions
@@ -168,7 +168,7 @@ public class Renderers {
public static TabledDescriptorRenderer renderConflictingSubstitutionsInferenceError(ExtendedInferenceErrorData inferenceErrorData,
TabledDescriptorRenderer result) {
assert inferenceErrorData.constraintSystem.hasConflictingConstraints();
assert inferenceErrorData.constraintSystem.getStatus().hasConflictingConstraints();
Collection<CallableDescriptor> substitutedDescriptors = Lists.newArrayList();
Collection<TypeSubstitutor> substitutors = ConstraintsUtil.getSubstitutorsForConflictingParameters(
@@ -231,7 +231,7 @@ public class Renderers {
@Override
public boolean apply(@Nullable ConstraintPosition constraintPosition) {
assert constraintPosition != null;
return inferenceErrorData.constraintSystem.hasTypeConstructorMismatchAt(constraintPosition);
return inferenceErrorData.constraintSystem.getStatus().hasTypeConstructorMismatchAt(constraintPosition);
}
};
return renderer.table(TabledDescriptorRenderer.newTable()
@@ -131,7 +131,7 @@ public class CallResolverUtil {
// Expected type mismatch was reported before as 'TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH'
ConstraintSystem constraintSystem = callToComplete.getConstraintSystem();
if (constraintSystem != null && constraintSystem.hasOnlyExpectedTypeMismatch()) return false;
if (constraintSystem != null && constraintSystem.getStatus().hasOnlyExpectedTypeMismatch()) return false;
return true;
}
@@ -235,13 +235,13 @@ public class CandidateResolver {
updateSystemWithConstraintSystemCompleter(context, resolvedCall);
if (resolvedCall.getConstraintSystem().hasContradiction()) {
if (resolvedCall.getConstraintSystem().getStatus().hasContradiction()) {
return reportInferenceError(context);
}
updateSystemIfExpectedTypeIsUnit(context, resolvedCall);
boolean boundsAreSatisfied = updateSystemCheckingBounds(resolvedCall);
if (!resolvedCall.getConstraintSystem().isSuccessful()) {
if (!resolvedCall.getConstraintSystem().getStatus().isSuccessful()) {
return reportInferenceError(context);
}
if (!boundsAreSatisfied) {
@@ -283,8 +283,8 @@ public class CandidateResolver {
//todo improve error reporting with errors in constraints from completer
constraintSystemCompleter.completeConstraintSystem(constraintSystem, resolvedCall);
if (constraintSystem.hasTypeConstructorMismatchAt(ConstraintPosition.FROM_COMPLETER) ||
(constraintSystem.hasContradiction() && !backup.hasContradiction())) {
if (constraintSystem.getStatus().hasTypeConstructorMismatchAt(ConstraintPosition.FROM_COMPLETER) ||
(constraintSystem.getStatus().hasContradiction() && !backup.getStatus().hasContradiction())) {
resolvedCall.setConstraintSystem(backup);
}
@@ -299,11 +299,11 @@ public class CandidateResolver {
JetType returnType = resolvedCall.getCandidateDescriptor().getReturnType();
if (returnType == null) return;
if (!constraintSystem.isSuccessful() && context.expectedType == TypeUtils.UNIT_EXPECTED_TYPE) {
if (!constraintSystem.getStatus().isSuccessful() && context.expectedType == TypeUtils.UNIT_EXPECTED_TYPE) {
ConstraintSystemImpl copy = (ConstraintSystemImpl) constraintSystem.copy();
copy.addSupertypeConstraint(KotlinBuiltIns.getInstance().getUnitType(), returnType, ConstraintPosition.EXPECTED_TYPE_POSITION);
if (copy.isSuccessful()) {
if (copy.getStatus().isSuccessful()) {
constraintSystem = copy;
resolvedCall.setConstraintSystem(constraintSystem);
}
@@ -317,12 +317,12 @@ public class CandidateResolver {
assert constraintSystem != null;
if (ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, /*substituteOtherTypeParametersInBounds=*/true)
&& !constraintSystem.hasUnknownParameters()) {
&& !constraintSystem.getStatus().hasUnknownParameters()) {
return true;
}
ConstraintSystemImpl copy = (ConstraintSystemImpl) constraintSystem.copy();
copy.processDeclaredBoundConstraints();
if (copy.isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(copy, /*substituteOtherTypeParametersInBounds=*/true)) {
if (copy.getStatus().isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(copy, /*substituteOtherTypeParametersInBounds=*/true)) {
resolvedCall.setConstraintSystem(copy);
return true;
}
@@ -618,7 +618,7 @@ public class CandidateResolver {
// Solution
boolean hasContradiction = constraintSystem.hasContradiction();
boolean hasContradiction = constraintSystem.getStatus().hasContradiction();
boolean boundsAreSatisfied = ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, /*substituteOtherTypeParametersInBounds=*/false);
candidateCall.setHasUnknownTypeParameters(true);
if (!hasContradiction && boundsAreSatisfied) {
@@ -23,6 +23,7 @@ import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
import org.jetbrains.jet.lang.types.Variance;
import java.util.Collection;
import java.util.Set;
public interface ConstraintSystem {
@@ -56,61 +57,8 @@ public interface ConstraintSystem {
*/
void addSupertypeConstraint(@Nullable JetType constrainingType, @NotNull JetType subjectType, @NotNull ConstraintPosition constraintPosition);
/**
* Returns <tt>true</tt> if constraint system has a solution (has no contradiction and has enough information to infer each registered type variable).
*/
boolean isSuccessful();
/**
* Return <tt>true</tt> if constraint system has no contradiction (it can be not successful because of the lack of information for a type variable).
*/
boolean hasContradiction();
/**
* Returns <tt>true</tt> if type constraints for some type variable are contradicting. <p/>
*
* For example, for <pre>fun &lt;R&gt; foo(r: R, t: java.util.List&lt;R&gt;) {}</pre> in invocation <tt>foo(1, arrayList("s"))</tt>
* type variable <tt>R</tt> has two conflicting constraints: <p/>
* - <tt>"R is a supertype of Int"</tt> <p/>
* - <tt>"List&lt;R&gt; is a supertype of List&lt;String&gt;"</tt> which leads to <tt>"R is equal to String"</tt>
*/
boolean hasConflictingConstraints();
/**
* Returns <tt>true</tt> if there is no information for some registered type variable.
*
* For example, for <pre>fun &lt;E&gt; newList()</pre> in invocation <tt>"val nl = newList()"</tt>
* there is no information to infer type variable <tt>E</tt>.
*/
boolean hasUnknownParameters();
/**
* Returns <tt>true</tt> if some constraint cannot be processed because of type constructor mismatch.
*
* For example, for <pre>fun &lt;R&gt; foo(t: List&lt;R&gt;) {}</pre> in invocation <tt>foo(hashSet("s"))</tt>
* there is type constructor mismatch: <tt>"HashSet&lt;String&gt; cannot be a subtype of List&lt;R&gt;"</tt>.
*/
boolean hasTypeConstructorMismatch();
/**
* Returns <tt>true</tt> if there is type constructor mismatch error at a specific {@code constraintPosition}.
*
* For example, for <pre>fun &lt;R&gt; foo(t: List&lt;R&gt;) {}</pre> in invocation <tt>foo(hashSet("s"))</tt>
* there is type constructor mismatch: <tt>"HashSet&lt;String&gt; cannot be a subtype of List&lt;R&gt;"</tt>
* at a constraint position {@code ConstraintPosition.getValueParameterPosition(0)}.
*/
boolean hasTypeConstructorMismatchAt(@NotNull ConstraintPosition constraintPosition);
/**
* Returns <tt>true</tt> if there is type constructor mismatch only in {@link ConstraintPosition.EXPECTED_TYPE_POSITION}.
*/
boolean hasOnlyExpectedTypeMismatch();
/**
* Returns <tt>true</tt> if there is an error in constraining types. <p/>
* Is used not to generate type inference error if there was one in argument types.
*/
boolean hasErrorInConstrainingTypes();
@NotNull
ConstraintSystemStatus getStatus();
/**
* Returns the resulting type constraints of solving the constraint system for specific type variable. <p/>
@@ -57,6 +57,69 @@ public class ConstraintSystemImpl implements ConstraintSystem {
@Nullable
private ConstraintSystem systemWithoutExpectedTypeConstraint;
private final ConstraintSystemStatus constraintSystemStatus = new ConstraintSystemStatus() {
@Override
public boolean isSuccessful() {
return !hasContradiction() && !hasUnknownParameters();
}
@Override
public boolean hasContradiction() {
return hasTypeConstructorMismatch() || hasConflictingConstraints();
}
@Override
public boolean hasConflictingConstraints() {
for (TypeParameterDescriptor typeParameter : typeParameterConstraints.keySet()) {
TypeConstraints typeConstraints = getTypeConstraints(typeParameter);
if (typeConstraints != null && ConstraintsUtil.getValues(typeConstraints).size() > 1) return true;
}
return false;
}
@Override
public boolean hasUnknownParameters() {
for (TypeConstraintsImpl constraints : typeParameterConstraints.values()) {
if (constraints.isEmpty()) {
return true;
}
}
return false;
}
@Override
public boolean hasTypeConstructorMismatch() {
return !errorConstraintPositions.isEmpty();
}
@Override
public boolean hasTypeConstructorMismatchAt(@NotNull ConstraintPosition constraintPosition) {
return errorConstraintPositions.contains(constraintPosition);
}
@Override
public boolean hasOnlyExpectedTypeMismatch() {
if (systemWithoutExpectedTypeConstraint == null) {
// the expected type constraint isn't added, there can't be an error with it
return false;
}
if (!isSuccessful() && systemWithoutExpectedTypeConstraint.getStatus().isSuccessful()) {
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
public boolean hasErrorInConstrainingTypes() {
return hasErrorInConstrainingTypes;
}
};
public ConstraintSystemImpl() {
this.resultingSubstitutor = createTypeSubstitutorWithDefaultForUnknownTypeParameter(new TypeProjection(CANT_INFER_TYPE_PARAMETER));
this.currentSubstitutor = createTypeSubstitutorWithDefaultForUnknownTypeParameter(new TypeProjection(DONT_CARE));
@@ -93,36 +156,10 @@ public class ConstraintSystemImpl implements ConstraintSystem {
});
}
@NotNull
@Override
public boolean hasTypeConstructorMismatch() {
return !errorConstraintPositions.isEmpty();
}
@Override
public boolean hasTypeConstructorMismatchAt(@NotNull ConstraintPosition constraintPosition) {
return errorConstraintPositions.contains(constraintPosition);
}
@Override
public boolean hasOnlyExpectedTypeMismatch() {
if (systemWithoutExpectedTypeConstraint == null) {
// the expected type constraint isn't added, there can't be an error with it
return false;
}
if (!isSuccessful() && systemWithoutExpectedTypeConstraint.isSuccessful()) {
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
public boolean hasErrorInConstrainingTypes() {
return hasErrorInConstrainingTypes;
public ConstraintSystemStatus getStatus() {
return constraintSystemStatus;
}
@Override
@@ -345,39 +382,10 @@ public class ConstraintSystemImpl implements ConstraintSystem {
return descriptor instanceof TypeParameterDescriptor && typeParameterConstraints.get(descriptor) != null;
}
@Override
public boolean isSuccessful() {
return !hasContradiction() && !hasUnknownParameters();
}
@Override
public boolean hasContradiction() {
return hasTypeConstructorMismatch() || hasConflictingConstraints();
}
@Override
public boolean hasConflictingConstraints() {
for (TypeParameterDescriptor typeParameter : typeParameterConstraints.keySet()) {
TypeConstraints typeConstraints = getTypeConstraints(typeParameter);
if (typeConstraints != null && ConstraintsUtil.getValues(typeConstraints).size() > 1) return true;
}
return false;
}
@Override
public boolean hasUnknownParameters() {
for (TypeConstraintsImpl constraints : typeParameterConstraints.values()) {
if (constraints.isEmpty()) {
return true;
}
}
return false;
}
@NotNull
@Override
public TypeSubstitutor getResultingSubstitutor() {
if (hasOnlyExpectedTypeMismatch()) {
if (getStatus().hasOnlyExpectedTypeMismatch()) {
assert systemWithoutExpectedTypeConstraint != null;
return systemWithoutExpectedTypeConstraint.getResultingSubstitutor();
}
@@ -0,0 +1,81 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.resolve.calls.inference;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
public interface ConstraintSystemStatus {
/**
* Returns <tt>true</tt> if constraint system has a solution (has no contradiction and has enough information to infer each registered type variable).
*/
boolean isSuccessful();
/**
* Return <tt>true</tt> if constraint system has no contradiction (it can be not successful because of the lack of information for a type variable).
*/
boolean hasContradiction();
/**
* Returns <tt>true</tt> if type constraints for some type variable are contradicting. <p/>
*
* For example, for <pre>fun &lt;R&gt; foo(r: R, t: java.util.List&lt;R&gt;) {}</pre> in invocation <tt>foo(1, arrayList("s"))</tt>
* type variable <tt>R</tt> has two conflicting constraints: <p/>
* - <tt>"R is a supertype of Int"</tt> <p/>
* - <tt>"List&lt;R&gt; is a supertype of List&lt;String&gt;"</tt> which leads to <tt>"R is equal to String"</tt>
*/
boolean hasConflictingConstraints();
/**
* Returns <tt>true</tt> if there is no information for some registered type variable.
*
* For example, for <pre>fun &lt;E&gt; newList()</pre> in invocation <tt>"val nl = newList()"</tt>
* there is no information to infer type variable <tt>E</tt>.
*/
boolean hasUnknownParameters();
/**
* Returns <tt>true</tt> if some constraint cannot be processed because of type constructor mismatch.
*
* For example, for <pre>fun &lt;R&gt; foo(t: List&lt;R&gt;) {}</pre> in invocation <tt>foo(hashSet("s"))</tt>
* there is type constructor mismatch: <tt>"HashSet&lt;String&gt; cannot be a subtype of List&lt;R&gt;"</tt>.
*/
boolean hasTypeConstructorMismatch();
/**
* Returns <tt>true</tt> if there is type constructor mismatch error at a specific {@code constraintPosition}.
*
* For example, for <pre>fun &lt;R&gt; foo(t: List&lt;R&gt;) {}</pre> in invocation <tt>foo(hashSet("s"))</tt>
* there is type constructor mismatch: <tt>"HashSet&lt;String&gt; cannot be a subtype of List&lt;R&gt;"</tt>
* at a constraint position {@code ConstraintPosition.getValueParameterPosition(0)}.
*/
boolean hasTypeConstructorMismatchAt(@NotNull ConstraintPosition constraintPosition);
/**
* Returns <tt>true</tt> if there is type constructor mismatch only in {@link ConstraintPosition.EXPECTED_TYPE_POSITION}.
*/
boolean hasOnlyExpectedTypeMismatch();
/**
* Returns <tt>true</tt> if there is an error in constraining types. <p/>
* Is used not to generate type inference error if there was one in argument types.
*/
boolean hasErrorInConstrainingTypes();
}
@@ -17,9 +17,11 @@
package org.jetbrains.jet.lang.resolve.calls.inference;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.Variance;
import java.util.Collection;
import java.util.Set;
public interface TypeConstraints {
@@ -25,6 +25,7 @@ import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemStatus;
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.VariableAsFunctionResolvedCall;
@@ -214,14 +215,15 @@ public class TracingStrategyImpl implements TracingStrategy {
@Override
public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData.ExtendedInferenceErrorData data) {
ConstraintSystem constraintSystem = data.constraintSystem;
assert !constraintSystem.isSuccessful() : "Report error only for not successful constraint system";
ConstraintSystemStatus status = constraintSystem.getStatus();
assert !status.isSuccessful() : "Report error only for not successful constraint system";
if (constraintSystem.hasErrorInConstrainingTypes()) {
if (status.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;
}
if (constraintSystem.hasOnlyExpectedTypeMismatch()) {
if (status.hasOnlyExpectedTypeMismatch()) {
JetType declaredReturnType = data.descriptor.getReturnType();
if (declaredReturnType == null) return;
@@ -231,14 +233,14 @@ public class TracingStrategyImpl implements TracingStrategy {
assert !noExpectedType(data.expectedType) : "Expected type doesn't exist, but there is an expected type mismatch error";
trace.report(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.on(reference, data.expectedType, substitutedReturnType));
}
else if (constraintSystem.hasTypeConstructorMismatch()) {
else if (status.hasTypeConstructorMismatch()) {
trace.report(TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH.on(reference, data));
}
else if (constraintSystem.hasConflictingConstraints()) {
else if (status.hasConflictingConstraints()) {
trace.report(TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS.on(reference, data));
}
else {
assert constraintSystem.hasUnknownParameters();
assert status.hasUnknownParameters();
trace.report(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER.on(reference, data));
}
}
@@ -250,7 +250,7 @@ public class TypeUtils {
}
constraintSystem.addSubtypeConstraint(withParameters, expected, ConstraintPosition.SPECIAL);
return constraintSystem.isSuccessful();
return constraintSystem.getStatus().isSuccessful();
}
private static void processAllTypeParameters(JetType type, Variance howThiTypeIsUsed, Processor<TypeParameterUsage> result) {
@@ -33,6 +33,7 @@ import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemStatus;
import org.jetbrains.jet.lang.resolve.calls.inference.InferenceErrorData;
import org.jetbrains.jet.lang.resolve.calls.model.MutableDataFlowInfoForArguments;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
@@ -337,12 +338,13 @@ public class ControlStructureTypingUtils {
@NotNull BindingTrace trace, @NotNull InferenceErrorData.ExtendedInferenceErrorData data
) {
ConstraintSystem constraintSystem = data.constraintSystem;
assert !constraintSystem.isSuccessful() : "Report error only for not successful constraint system";
ConstraintSystemStatus status = constraintSystem.getStatus();
assert !status.isSuccessful() : "Report error only for not successful constraint system";
if (constraintSystem.hasErrorInConstrainingTypes()) {
if (status.hasErrorInConstrainingTypes()) {
return;
}
if (constraintSystem.hasOnlyExpectedTypeMismatch() || constraintSystem.hasConflictingConstraints()) {
if (status.hasOnlyExpectedTypeMismatch() || status.hasConflictingConstraints()) {
JetExpression expression = call.getCalleeExpression();
if (expression != null) {
expression.accept(checkTypeVisitor, new CheckTypeContext(trace, data.expectedType));
@@ -310,7 +310,7 @@ public class ExpressionTypingUtils {
}
constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.getType(), ConstraintPosition.RECEIVER_POSITION);
return constraintSystem.isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, true);
return constraintSystem.getStatus().isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, true);
}
private static Set<Name> collectUsedTypeNames(@NotNull JetType jetType) {