Minor refactoring while working on prioritized constraints
This commit is contained in:
@@ -5,7 +5,7 @@ import com.intellij.openapi.application.ApplicationManager;
|
|||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl;
|
import org.jetbrains.jet.lang.resolve.calls.inference.BoundsOwner;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemSolution;
|
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemSolution;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.util.slicedmap.*;
|
import org.jetbrains.jet.util.slicedmap.*;
|
||||||
@@ -22,8 +22,8 @@ public class ResolutionDebugInfo {
|
|||||||
public static final WritableSlice<One, ResolvedCall<? extends CallableDescriptor>> RESULT = Slices.createSimpleSlice();
|
public static final WritableSlice<One, ResolvedCall<? extends CallableDescriptor>> RESULT = Slices.createSimpleSlice();
|
||||||
public static final WritableSlice<One, StringBuilder> ERRORS = Slices.createSimpleSlice();
|
public static final WritableSlice<One, StringBuilder> ERRORS = Slices.createSimpleSlice();
|
||||||
public static final WritableSlice<One, StringBuilder> LOG = Slices.createSimpleSlice();
|
public static final WritableSlice<One, StringBuilder> LOG = Slices.createSimpleSlice();
|
||||||
public static final WritableSlice<One, Map<TypeParameterDescriptor, ConstraintSystemImpl.TypeValue>> BOUNDS_FOR_UNKNOWNS = Slices.createSimpleSlice();
|
public static final WritableSlice<One, Map<TypeParameterDescriptor, BoundsOwner>> BOUNDS_FOR_UNKNOWNS = Slices.createSimpleSlice();
|
||||||
public static final WritableSlice<One, Map<JetType, ConstraintSystemImpl.TypeValue>> BOUNDS_FOR_KNOWNS = Slices.createSimpleSlice();
|
public static final WritableSlice<One, Map<JetType, BoundsOwner>> BOUNDS_FOR_KNOWNS = Slices.createSimpleSlice();
|
||||||
public static final WritableSlice<One, ConstraintSystemSolution> SOLUTION = Slices.createSimpleSlice();
|
public static final WritableSlice<One, ConstraintSystemSolution> SOLUTION = Slices.createSimpleSlice();
|
||||||
public static final WritableSlice<One, Collection<TypeParameterDescriptor>> UNKNOWNS = Slices.createSimpleSlice();
|
public static final WritableSlice<One, Collection<TypeParameterDescriptor>> UNKNOWNS = Slices.createSimpleSlice();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.jetbrains.jet.lang.resolve.calls.inference;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
*/
|
||||||
|
public interface BoundsOwner {
|
||||||
|
@NotNull
|
||||||
|
Set<TypeValue> getUpperBounds();
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
Set<TypeValue> getLowerBounds();
|
||||||
|
}
|
||||||
+8
-8
@@ -12,11 +12,11 @@ public interface ConstraintResolutionListener {
|
|||||||
|
|
||||||
public static final ConstraintResolutionListener DO_NOTHING = new ConstraintResolutionListener() {
|
public static final ConstraintResolutionListener DO_NOTHING = new ConstraintResolutionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, ConstraintSystemImpl.TypeValue typeValue) {
|
public void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, BoundsOwner typeValue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void constraintsForKnownType(JetType type, ConstraintSystemImpl.TypeValue typeValue) {
|
public void constraintsForKnownType(JetType type, BoundsOwner typeValue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -24,18 +24,18 @@ public interface ConstraintResolutionListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void log(Object message) {
|
public void log(Object... messageFragments) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void error(Object message) {
|
public void error(Object... messageFragments) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, ConstraintSystemImpl.TypeValue typeValue);
|
void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, BoundsOwner typeValue);
|
||||||
void constraintsForKnownType(JetType type, ConstraintSystemImpl.TypeValue typeValue);
|
void constraintsForKnownType(JetType type, BoundsOwner typeValue);
|
||||||
void done(ConstraintSystemSolution solution, Set<TypeParameterDescriptor> typeParameterDescriptors);
|
void done(ConstraintSystemSolution solution, Set<TypeParameterDescriptor> typeParameterDescriptors);
|
||||||
|
|
||||||
void log(Object message);
|
void log(Object... messageFragments);
|
||||||
void error(Object message);
|
void error(Object... messageFragments);
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-16
@@ -143,7 +143,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
listener.log("minimal solution from lowerbounds for " + this + " is " + commonSupertype);
|
listener.log("minimal solution from lowerbounds for ", this, " is ", commonSupertype);
|
||||||
value = new KnownType(commonSupertype);
|
value = new KnownType(commonSupertype);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -247,10 +247,10 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, TypeCheckingProcedure typeCheckingProcedure) {
|
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, @NotNull TypeCheckingProcedure typeCheckingProcedure) {
|
||||||
boolean result = delegate.assertEqualTypes(a, b, typeCheckingProcedure);
|
boolean result = delegate.assertEqualTypes(a, b, typeCheckingProcedure);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
listener.error("-- Failed to equate " + a + " and " + b);
|
listener.error("-- Failed to equate ", a, " and ", b);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -259,16 +259,16 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
public boolean assertEqualTypeConstructors(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
|
public boolean assertEqualTypeConstructors(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
|
||||||
boolean result = delegate.assertEqualTypeConstructors(a, b);
|
boolean result = delegate.assertEqualTypeConstructors(a, b);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
listener.error("-- Type constructors are not equal: " + a + " and " + b);
|
listener.error("-- Type constructors are not equal: ", a, " and ", b);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, TypeCheckingProcedure typeCheckingProcedure) {
|
public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeCheckingProcedure typeCheckingProcedure) {
|
||||||
boolean result = delegate.assertSubtype(subtype, supertype, typeCheckingProcedure);
|
boolean result = delegate.assertSubtype(subtype, supertype, typeCheckingProcedure);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
listener.error("-- " + subtype + " can't be a subtype of " + supertype);
|
listener.error("-- ", subtype, " can't be a subtype of ", supertype);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -277,7 +277,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
public boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) {
|
public boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
boolean result = delegate.noCorrespondingSupertype(subtype, supertype);
|
boolean result = delegate.noCorrespondingSupertype(subtype, supertype);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
listener.error("-- " + subtype + " has no supertype corresponding to " + supertype);
|
listener.error("-- ", subtype, " has no supertype corresponding to ", supertype);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -294,7 +294,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
private TypeCheckingProcedure createConstraintExpander() {
|
private TypeCheckingProcedure createConstraintExpander() {
|
||||||
return new TypeCheckingProcedure(new TypeConstraintBuilderAdapter(new TypingConstraints() {
|
return new TypeCheckingProcedure(new TypeConstraintBuilderAdapter(new TypingConstraints() {
|
||||||
@Override
|
@Override
|
||||||
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, TypeCheckingProcedure typeCheckingProcedure) {
|
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, @NotNull TypeCheckingProcedure typeCheckingProcedure) {
|
||||||
TypeValue aValue = getTypeValueFor(a);
|
TypeValue aValue = getTypeValueFor(a);
|
||||||
TypeValue bValue = getTypeValueFor(b);
|
TypeValue bValue = getTypeValueFor(b);
|
||||||
|
|
||||||
@@ -309,7 +309,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, TypeCheckingProcedure typeCheckingProcedure) {
|
public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeCheckingProcedure typeCheckingProcedure) {
|
||||||
TypeValue subtypeValue = getTypeValueFor(subtype);
|
TypeValue subtypeValue = getTypeValueFor(subtype);
|
||||||
TypeValue supertypeValue = getTypeValueFor(supertype);
|
TypeValue supertypeValue = getTypeValueFor(supertype);
|
||||||
|
|
||||||
@@ -389,7 +389,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void addSubtypingConstraintOnTypeValues(TypeValue typeValueForLower, TypeValue typeValueForUpper) {
|
private void addSubtypingConstraintOnTypeValues(TypeValue typeValueForLower, TypeValue typeValueForUpper) {
|
||||||
listener.log("Constraint added: " + typeValueForLower + " :< " + typeValueForUpper);
|
listener.log("Constraint added: ", typeValueForLower, " :< ", typeValueForUpper);
|
||||||
if (typeValueForLower != typeValueForUpper) {
|
if (typeValueForLower != typeValueForUpper) {
|
||||||
typeValueForLower.addUpperBound(typeValueForUpper);
|
typeValueForLower.addUpperBound(typeValueForUpper);
|
||||||
typeValueForUpper.addLowerBound(typeValueForLower);
|
typeValueForUpper.addLowerBound(typeValueForLower);
|
||||||
@@ -409,7 +409,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
KnownType knownBoundType = (KnownType) upperBound;
|
KnownType knownBoundType = (KnownType) upperBound;
|
||||||
boolean ok = constraintExpander.isSubtypeOf(jetType, knownBoundType.getType());
|
boolean ok = constraintExpander.isSubtypeOf(jetType, knownBoundType.getType());
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
listener.error("Error while expanding '" + jetType + " :< " + knownBoundType.getType() + "'");
|
listener.error("Error while expanding '", jetType, " :< ", knownBoundType.getType(), "'");
|
||||||
return new Solution().registerError("Mismatch while expanding constraints");
|
return new Solution().registerError("Mismatch while expanding constraints");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -443,11 +443,11 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (UnknownType unknownType : unknownTypes.values()) {
|
for (UnknownType unknownType : unknownTypes.values()) {
|
||||||
listener.constraintsForUnknown(unknownType.getTypeParameterDescriptor(), unknownType);
|
// listener.constraintsForUnknown(unknownType.getTypeParameterDescriptor(), unknownType);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (KnownType knownType : knownTypes.values()) {
|
for (KnownType knownType : knownTypes.values()) {
|
||||||
listener.constraintsForKnownType(knownType.getType(), knownType);
|
// listener.constraintsForKnownType(knownType.getType(), knownType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find inconsistencies
|
// Find inconsistencies
|
||||||
@@ -477,14 +477,14 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
JetType boundingType = solution.getSubstitutor().substitute(upperBound.getValue().getType(), Variance.INVARIANT);
|
JetType boundingType = solution.getSubstitutor().substitute(upperBound.getValue().getType(), Variance.INVARIANT);
|
||||||
if (!typeChecker.isSubtypeOf(type, boundingType)) { // TODO
|
if (!typeChecker.isSubtypeOf(type, boundingType)) { // TODO
|
||||||
solution.registerError("Constraint violation: " + type + " is not a subtype of " + boundingType);
|
solution.registerError("Constraint violation: " + type + " is not a subtype of " + boundingType);
|
||||||
listener.error("Constraint violation: " + type + " :< " + boundingType);
|
listener.error("Constraint violation: ", type, " :< ", boundingType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (TypeValue lowerBound : typeValue.getLowerBounds()) {
|
for (TypeValue lowerBound : typeValue.getLowerBounds()) {
|
||||||
JetType boundingType = solution.getSubstitutor().substitute(lowerBound.getValue().getType(), Variance.INVARIANT);
|
JetType boundingType = solution.getSubstitutor().substitute(lowerBound.getValue().getType(), Variance.INVARIANT);
|
||||||
if (!typeChecker.isSubtypeOf(boundingType, type)) {
|
if (!typeChecker.isSubtypeOf(boundingType, type)) {
|
||||||
solution.registerError("Constraint violation: " + boundingType + " is not a subtype of " + type);
|
solution.registerError("Constraint violation: " + boundingType + " is not a subtype of " + type);
|
||||||
listener.error("Constraint violation: " + boundingType + " :< " + type);
|
listener.error("Constraint violation: ", boundingType, " :< ", type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -542,7 +542,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
|
|
||||||
TypeProjection typeProjection = new TypeProjection(getValue(descriptor));
|
TypeProjection typeProjection = new TypeProjection(getValue(descriptor));
|
||||||
|
|
||||||
listener.log(descriptor + " |-> " + typeProjection);
|
listener.log(descriptor, " |-> ", typeProjection);
|
||||||
|
|
||||||
return typeProjection;
|
return typeProjection;
|
||||||
}
|
}
|
||||||
|
|||||||
+470
@@ -0,0 +1,470 @@
|
|||||||
|
package org.jetbrains.jet.lang.resolve.calls.inference;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.types.*;
|
||||||
|
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||||
|
import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure;
|
||||||
|
import org.jetbrains.jet.lang.types.checker.TypingConstraints;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintType.PARAMETER_BOUND;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
*/
|
||||||
|
public class ConstraintSystemWithPriorities implements ConstraintSystem {
|
||||||
|
|
||||||
|
public static final Comparator<SubtypingConstraint> SUBTYPING_CONSTRAINT_ORDER = new Comparator<SubtypingConstraint>() {
|
||||||
|
@Override
|
||||||
|
public int compare(SubtypingConstraint o1, SubtypingConstraint o2) {
|
||||||
|
return o1.getType().compareTo(o2.getType());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static class LoopInTypeVariableConstraintsException extends RuntimeException {
|
||||||
|
public LoopInTypeVariableConstraintsException() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================================================================================================
|
||||||
|
|
||||||
|
private final Map<JetType, TypeValue> knownTypes = Maps.newLinkedHashMap(); // linked - for easier debugging
|
||||||
|
private final Map<TypeParameterDescriptor, TypeValue> unknownTypes = Maps.newLinkedHashMap(); // linked - for easier debugging
|
||||||
|
private final Set<TypeValue> unsolvedUnknowns = Sets.newLinkedHashSet(); // linked - for easier debugging
|
||||||
|
private final PriorityQueue<SubtypingConstraint> constraintQueue = new PriorityQueue<SubtypingConstraint>(10, SUBTYPING_CONSTRAINT_ORDER);
|
||||||
|
|
||||||
|
private final JetTypeChecker typeChecker = JetTypeChecker.INSTANCE;
|
||||||
|
private final TypeCheckingProcedure constraintExpander;
|
||||||
|
private final ConstraintResolutionListener listener;
|
||||||
|
|
||||||
|
public ConstraintSystemWithPriorities(ConstraintResolutionListener listener) {
|
||||||
|
this.listener = listener;
|
||||||
|
this.constraintExpander = createConstraintExpander();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private TypeValue getTypeValueFor(@NotNull JetType type) {
|
||||||
|
DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor();
|
||||||
|
if (declarationDescriptor instanceof TypeParameterDescriptor) {
|
||||||
|
TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor;
|
||||||
|
// Checking that this is not a T?, but exactly T
|
||||||
|
if (typeParameterDescriptor.getDefaultType().isNullable() == type.isNullable()) {
|
||||||
|
TypeValue unknownType = unknownTypes.get(typeParameterDescriptor);
|
||||||
|
if (unknownType != null) {
|
||||||
|
return unknownType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeValue typeValue = knownTypes.get(type);
|
||||||
|
if (typeValue == null) {
|
||||||
|
typeValue = new TypeValue(type);
|
||||||
|
knownTypes.put(type, typeValue);
|
||||||
|
}
|
||||||
|
return typeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerTypeVariable(@NotNull TypeParameterDescriptor typeParameterDescriptor, @NotNull Variance positionVariance) {
|
||||||
|
assert !unknownTypes.containsKey(typeParameterDescriptor);
|
||||||
|
TypeValue typeValue = new TypeValue(typeParameterDescriptor, positionVariance);
|
||||||
|
unknownTypes.put(typeParameterDescriptor, typeValue);
|
||||||
|
unsolvedUnknowns.add(typeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private TypeValue getTypeVariable(TypeParameterDescriptor typeParameterDescriptor) {
|
||||||
|
TypeValue unknownType = unknownTypes.get(typeParameterDescriptor);
|
||||||
|
if (unknownType == null) {
|
||||||
|
throw new IllegalArgumentException("This type parameter is not an unknown in this constraint system: " + typeParameterDescriptor);
|
||||||
|
}
|
||||||
|
return unknownType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addSubtypingConstraint(@NotNull SubtypingConstraint constraint) {
|
||||||
|
constraintQueue.add(constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constraint expansion
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
private TypeCheckingProcedure createConstraintExpander() {
|
||||||
|
return new TypeCheckingProcedure(new TypeConstraintBuilderAdapter(new TypingConstraints() {
|
||||||
|
@Override
|
||||||
|
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, @NotNull TypeCheckingProcedure typeCheckingProcedure) {
|
||||||
|
TypeValue aValue = getTypeValueFor(a);
|
||||||
|
TypeValue bValue = getTypeValueFor(b);
|
||||||
|
|
||||||
|
return expandEqualityConstraint(aValue, bValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean assertEqualTypeConstructors(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
|
||||||
|
return a.equals(b)
|
||||||
|
|| unknownTypes.containsKey(a.getDeclarationDescriptor())
|
||||||
|
|| unknownTypes.containsKey(b.getDeclarationDescriptor());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeCheckingProcedure typeCheckingProcedure) {
|
||||||
|
TypeValue subtypeValue = getTypeValueFor(subtype);
|
||||||
|
TypeValue supertypeValue = getTypeValueFor(supertype);
|
||||||
|
|
||||||
|
if (someUnknown(subtypeValue, supertypeValue)) {
|
||||||
|
expandSubtypingConstraint(subtypeValue, supertypeValue);
|
||||||
|
}
|
||||||
|
return true; // For known types further expansion happens automatically
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
|
// If some of the types is an unknown, the constraint must be generated, and we should carry on
|
||||||
|
// otherwise there can be no solution, and we should fail
|
||||||
|
TypeValue subTypeValue = getTypeValueFor(subtype);
|
||||||
|
TypeValue superTypeValue = getTypeValueFor(supertype);
|
||||||
|
boolean someUnknown = someUnknown(subTypeValue, superTypeValue);
|
||||||
|
if (someUnknown) {
|
||||||
|
expandSubtypingConstraint(subTypeValue, superTypeValue);
|
||||||
|
}
|
||||||
|
return someUnknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean someUnknown(TypeValue subtypeValue, TypeValue supertypeValue) {
|
||||||
|
return !subtypeValue.isKnown() || !supertypeValue.isKnown();
|
||||||
|
}
|
||||||
|
|
||||||
|
}, listener));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean assignValueTo(TypeValue unknown, JetType value) {
|
||||||
|
if (unknown.hasValue()) {
|
||||||
|
// If we have already assigned a value to this unknown,
|
||||||
|
// it is a conflict to assign another one, unless this new one is equal to the previous
|
||||||
|
return TypeUtils.equalTypes(unknown.getType(), value);
|
||||||
|
}
|
||||||
|
unsolvedUnknowns.remove(unknown);
|
||||||
|
unknown.setValue(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean mergeUnknowns(@NotNull TypeValue a, @NotNull TypeValue b) {
|
||||||
|
assert !a.isKnown() && !b.isKnown();
|
||||||
|
listener.error("!!!mergeUnknowns() is not implemented!!!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean expandEqualityConstraint(TypeValue a, TypeValue b) {
|
||||||
|
if (a.isKnown() && b.isKnown()) {
|
||||||
|
return constraintExpander.equalTypes(a.getType(), b.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
// At least one of them is unknown
|
||||||
|
if (a.isKnown()) {
|
||||||
|
TypeValue tmp = a;
|
||||||
|
a = b;
|
||||||
|
b = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now a is definitely unknown
|
||||||
|
if (b.isKnown()) {
|
||||||
|
return assignValueTo(a, b.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
// They are both unknown
|
||||||
|
return mergeUnknowns(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean expandSubtypingConstraint(TypeValue lower, TypeValue upper) {
|
||||||
|
listener.log("Constraint added: ", lower, " :< ", upper);
|
||||||
|
|
||||||
|
if (lower == upper) return true;
|
||||||
|
|
||||||
|
// Remember for a later check
|
||||||
|
lower.addUpperBound(upper);
|
||||||
|
upper.addLowerBound(lower);
|
||||||
|
|
||||||
|
if (lower.isKnown() && upper.isKnown()) {
|
||||||
|
// Two known types: expand constraints
|
||||||
|
return constraintExpander.isSubtypeOf(lower.getType(), upper.getType());
|
||||||
|
}
|
||||||
|
else if (!lower.isKnown() && !upper.isKnown()) {
|
||||||
|
// Two unknown types: merge them into one variable
|
||||||
|
return mergeUnknowns(lower, upper);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// One unknown and one known
|
||||||
|
if (upper.isKnown()) {
|
||||||
|
if (TypeUtils.canHaveSubtypes(typeChecker, upper.getType())) {
|
||||||
|
// Upper bound is final -> we have to equate the lower bounds to it
|
||||||
|
return expandEqualityConstraint(lower, upper);
|
||||||
|
}
|
||||||
|
if (lower.getLowerBounds().contains(upper)) {
|
||||||
|
// upper :< lower :< upper
|
||||||
|
return expandEqualityConstraint(lower, upper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (upper.getUpperBounds().contains(lower)) {
|
||||||
|
// lower :< upper :< lower
|
||||||
|
return expandEqualityConstraint(lower, upper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public ConstraintSystemSolution solve() {
|
||||||
|
Solution solution = new Solution();
|
||||||
|
// At this point we only have type values, no bounds added for them, no values computed for unknown types
|
||||||
|
|
||||||
|
// Generate low-priority constraints from bounds
|
||||||
|
for (Map.Entry<TypeParameterDescriptor, TypeValue> entry : Sets.newHashSet(unknownTypes.entrySet())) {
|
||||||
|
TypeParameterDescriptor typeParameterDescriptor = entry.getKey();
|
||||||
|
TypeValue typeValue = entry.getValue();
|
||||||
|
for (JetType upperBound : typeParameterDescriptor.getUpperBounds()) {
|
||||||
|
addSubtypingConstraint(PARAMETER_BOUND.assertSubtyping(typeValue.getOriginalType(), getTypeValueFor(upperBound).getOriginalType()));
|
||||||
|
}
|
||||||
|
for (JetType lowerBound : typeParameterDescriptor.getLowerBounds()) {
|
||||||
|
addSubtypingConstraint(PARAMETER_BOUND.assertSubtyping(getTypeValueFor(lowerBound).getOriginalType(), typeValue.getOriginalType()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expand and solve constraints
|
||||||
|
while (!constraintQueue.isEmpty()) {
|
||||||
|
SubtypingConstraint constraint = constraintQueue.poll();
|
||||||
|
|
||||||
|
// Apply constraint
|
||||||
|
TypeValue lower = getTypeValueFor(constraint.getSubtype());
|
||||||
|
TypeValue upper = getTypeValueFor(constraint.getSupertype());
|
||||||
|
boolean success = expandSubtypingConstraint(lower, upper);
|
||||||
|
if (!success) {
|
||||||
|
solution.registerError(constraint.getErrorMessage());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (???) Propagate info
|
||||||
|
|
||||||
|
// Any unknowns left?
|
||||||
|
if (unsolvedUnknowns.isEmpty()) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, let's check the rest of the constraints
|
||||||
|
|
||||||
|
// Expand custom bounds, e.g. List<T> <: List<Int>
|
||||||
|
// for (Map.Entry<JetType, TypeValue> entry : Sets.newHashSet(knownTypes.entrySet())) {
|
||||||
|
// JetType jetType = entry.getKey();
|
||||||
|
// TypeValue typeValue = entry.getValue();
|
||||||
|
//
|
||||||
|
// for (TypeValue upperBound : typeValue.getUpperBounds()) {
|
||||||
|
// if (upperBound.isKnown()) {
|
||||||
|
// boolean ok = constraintExpander.isSubtypeOf(jetType, upperBound.getType());
|
||||||
|
// if (!ok) {
|
||||||
|
// listener.error("Error while expanding '" + jetType + " :< " + upperBound.getType() + "'");
|
||||||
|
// return new Solution().registerError("Mismatch while expanding constraints");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Lower bounds. Probably not needed for known types, as everything is symmetrical anyway
|
||||||
|
// }
|
||||||
|
|
||||||
|
// effective bounds for each node
|
||||||
|
// Set<TypeValue> visited = Sets.newHashSet();
|
||||||
|
// for (TypeValue unknownType : unknownTypes.values()) {
|
||||||
|
// transitiveClosure(unknownType, visited);
|
||||||
|
// }
|
||||||
|
|
||||||
|
for (TypeValue unknownType : unknownTypes.values()) {
|
||||||
|
listener.constraintsForUnknown(unknownType.getTypeParameterDescriptor(), unknownType);
|
||||||
|
}
|
||||||
|
for (TypeValue knownType : knownTypes.values()) {
|
||||||
|
listener.constraintsForKnownType(knownType.getType(), knownType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find inconsistencies
|
||||||
|
|
||||||
|
// Compute values and check that all bounds are respected by solutions:
|
||||||
|
// we have set some of them from equality constraints with known types
|
||||||
|
// and thus the bounds may be violated if some of the constraints conflict
|
||||||
|
for (TypeValue unknownType : unknownTypes.values()) {
|
||||||
|
check(unknownType, solution);
|
||||||
|
}
|
||||||
|
for (TypeValue knownType : knownTypes.values()) {
|
||||||
|
check(knownType, solution);
|
||||||
|
}
|
||||||
|
|
||||||
|
listener.done(solution, unknownTypes.keySet());
|
||||||
|
|
||||||
|
return solution;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void transitiveClosure(TypeValue current, Set<TypeValue> visited) {
|
||||||
|
if (!visited.add(current)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TypeValue upperBound : Sets.newHashSet(current.getUpperBounds())) {
|
||||||
|
if (upperBound.isKnown()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
transitiveClosure(upperBound, visited);
|
||||||
|
Set<TypeValue> upperBounds = upperBound.getUpperBounds();
|
||||||
|
for (TypeValue transitiveBound : upperBounds) {
|
||||||
|
expandSubtypingConstraint(current, transitiveBound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void check(TypeValue typeValue, Solution solution) {
|
||||||
|
try {
|
||||||
|
JetType resultingType = typeValue.getType();
|
||||||
|
JetType type = solution.getSubstitutor().substitute(resultingType, Variance.INVARIANT); // TODO
|
||||||
|
for (TypeValue upperBound : typeValue.getUpperBounds()) {
|
||||||
|
JetType boundingType = solution.getSubstitutor().substitute(upperBound.getType(), Variance.INVARIANT);
|
||||||
|
if (!typeChecker.isSubtypeOf(type, boundingType)) { // TODO
|
||||||
|
solution.registerError("Constraint violation: " + type + " is not a subtype of " + boundingType);
|
||||||
|
listener.error("Constraint violation: ", type, " :< ", boundingType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (TypeValue lowerBound : typeValue.getLowerBounds()) {
|
||||||
|
JetType boundingType = solution.getSubstitutor().substitute(lowerBound.getType(), Variance.INVARIANT);
|
||||||
|
if (!typeChecker.isSubtypeOf(boundingType, type)) {
|
||||||
|
solution.registerError("Constraint violation: " + boundingType + " is not a subtype of " + type);
|
||||||
|
listener.error("Constraint violation: ", boundingType, " :< ", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (LoopInTypeVariableConstraintsException e) {
|
||||||
|
listener.error("Loop detected");
|
||||||
|
solution.registerError("[TODO] Loop in constraints");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Error implements SolutionStatus {
|
||||||
|
|
||||||
|
private final String message;
|
||||||
|
|
||||||
|
private Error(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSuccessful() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Solution implements ConstraintSystemSolution {
|
||||||
|
private final TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(new TypeSubstitutor.TypeSubstitution() {
|
||||||
|
@Override
|
||||||
|
public TypeProjection get(TypeConstructor key) {
|
||||||
|
DeclarationDescriptor declarationDescriptor = key.getDeclarationDescriptor();
|
||||||
|
if (declarationDescriptor instanceof TypeParameterDescriptor) {
|
||||||
|
TypeParameterDescriptor descriptor = (TypeParameterDescriptor) declarationDescriptor;
|
||||||
|
|
||||||
|
if (!unknownTypes.containsKey(descriptor)) return null;
|
||||||
|
|
||||||
|
TypeProjection typeProjection = new TypeProjection(getValue(descriptor));
|
||||||
|
|
||||||
|
listener.log(descriptor, " |-> ", typeProjection);
|
||||||
|
|
||||||
|
return typeProjection;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
private SolutionStatus status;
|
||||||
|
|
||||||
|
public Solution() {
|
||||||
|
this.status = SolutionStatus.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Solution registerError(String message) {
|
||||||
|
status = new Error(message);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public SolutionStatus getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetType getValue(TypeParameterDescriptor typeParameterDescriptor) {
|
||||||
|
return getTypeVariable(typeParameterDescriptor).getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public TypeSubstitutor getSubstitutor() {
|
||||||
|
return typeSubstitutor;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
private static final class TypeConstraintBuilderAdapter implements TypingConstraints {
|
||||||
|
private final TypingConstraints delegate;
|
||||||
|
private final ConstraintResolutionListener listener;
|
||||||
|
|
||||||
|
private TypeConstraintBuilderAdapter(TypingConstraints delegate, ConstraintResolutionListener listener) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, @NotNull TypeCheckingProcedure typeCheckingProcedure) {
|
||||||
|
boolean result = delegate.assertEqualTypes(a, b, typeCheckingProcedure);
|
||||||
|
if (!result) {
|
||||||
|
listener.error("-- Failed to equate ", a, " and ", b);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean assertEqualTypeConstructors(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
|
||||||
|
boolean result = delegate.assertEqualTypeConstructors(a, b);
|
||||||
|
if (!result) {
|
||||||
|
listener.error("-- Type constructors are not equal: ", a, " and ", b);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeCheckingProcedure typeCheckingProcedure) {
|
||||||
|
boolean result = delegate.assertSubtype(subtype, supertype, typeCheckingProcedure);
|
||||||
|
if (!result) {
|
||||||
|
listener.error("-- " + subtype + " can't be a subtype of " + supertype);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
|
boolean result = delegate.noCorrespondingSupertype(subtype, supertype);
|
||||||
|
if (!result) {
|
||||||
|
listener.error("-- " + subtype + " has no supertype corresponding to " + supertype);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+14
-8
@@ -23,9 +23,9 @@ public class DebugConstraintResolutionListener implements ConstraintResolutionLi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, ConstraintSystemImpl.TypeValue typeValue) {
|
public void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, BoundsOwner typeValue) {
|
||||||
if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return;
|
if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return;
|
||||||
Map<TypeParameterDescriptor, ConstraintSystemImpl.TypeValue> map = debugInfo.get(BOUNDS_FOR_UNKNOWNS);
|
Map<TypeParameterDescriptor, BoundsOwner> map = debugInfo.get(BOUNDS_FOR_UNKNOWNS);
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
map = Maps.newLinkedHashMap();
|
map = Maps.newLinkedHashMap();
|
||||||
debugInfo.set(BOUNDS_FOR_UNKNOWNS, map);
|
debugInfo.set(BOUNDS_FOR_UNKNOWNS, map);
|
||||||
@@ -34,9 +34,9 @@ public class DebugConstraintResolutionListener implements ConstraintResolutionLi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void constraintsForKnownType(JetType type, ConstraintSystemImpl.TypeValue typeValue) {
|
public void constraintsForKnownType(JetType type, BoundsOwner typeValue) {
|
||||||
if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return;
|
if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return;
|
||||||
Map<JetType,ConstraintSystemImpl.TypeValue> map = debugInfo.get(BOUNDS_FOR_KNOWNS);
|
Map<JetType,BoundsOwner> map = debugInfo.get(BOUNDS_FOR_KNOWNS);
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
map = Maps.newLinkedHashMap();
|
map = Maps.newLinkedHashMap();
|
||||||
debugInfo.set(BOUNDS_FOR_KNOWNS, map);
|
debugInfo.set(BOUNDS_FOR_KNOWNS, map);
|
||||||
@@ -52,24 +52,30 @@ public class DebugConstraintResolutionListener implements ConstraintResolutionLi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void log(Object message) {
|
public void log(Object... messageFragments) {
|
||||||
if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return;
|
if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return;
|
||||||
StringBuilder stringBuilder = debugInfo.get(LOG);
|
StringBuilder stringBuilder = debugInfo.get(LOG);
|
||||||
if (stringBuilder == null) {
|
if (stringBuilder == null) {
|
||||||
stringBuilder = new StringBuilder();
|
stringBuilder = new StringBuilder();
|
||||||
debugInfo.set(LOG, stringBuilder);
|
debugInfo.set(LOG, stringBuilder);
|
||||||
}
|
}
|
||||||
stringBuilder.append(message).append("\n");
|
for (Object m : messageFragments) {
|
||||||
|
stringBuilder.append(m);
|
||||||
|
}
|
||||||
|
stringBuilder.append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void error(Object message) {
|
public void error(Object... messageFragments) {
|
||||||
if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return;
|
if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return;
|
||||||
StringBuilder stringBuilder = debugInfo.get(ERRORS);
|
StringBuilder stringBuilder = debugInfo.get(ERRORS);
|
||||||
if (stringBuilder == null) {
|
if (stringBuilder == null) {
|
||||||
stringBuilder = new StringBuilder();
|
stringBuilder = new StringBuilder();
|
||||||
debugInfo.set(ERRORS, stringBuilder);
|
debugInfo.set(ERRORS, stringBuilder);
|
||||||
}
|
}
|
||||||
stringBuilder.append(message).append("\n");
|
for (Object m : messageFragments) {
|
||||||
|
stringBuilder.append(m);
|
||||||
|
}
|
||||||
|
stringBuilder.append("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-9
@@ -12,13 +12,13 @@ import java.util.Set;
|
|||||||
public class PrintingConstraintResolutionListener implements ConstraintResolutionListener {
|
public class PrintingConstraintResolutionListener implements ConstraintResolutionListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, ConstraintSystemImpl.TypeValue typeValue) {
|
public void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, BoundsOwner typeValue) {
|
||||||
println("Constraints for " + typeParameterDescriptor);
|
println("Constraints for " + typeParameterDescriptor);
|
||||||
printTypeValue(typeValue);
|
printTypeValue(typeValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void constraintsForKnownType(JetType type, ConstraintSystemImpl.TypeValue typeValue) {
|
public void constraintsForKnownType(JetType type, BoundsOwner typeValue) {
|
||||||
println("Constraints for " + type);
|
println("Constraints for " + type);
|
||||||
printTypeValue(typeValue);
|
printTypeValue(typeValue);
|
||||||
}
|
}
|
||||||
@@ -31,20 +31,24 @@ public class PrintingConstraintResolutionListener implements ConstraintResolutio
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void log(Object message) {
|
public void log(Object... messageFragments) {
|
||||||
println(message);
|
for (Object fragment : messageFragments) {
|
||||||
|
println(fragment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void error(Object message) {
|
public void error(Object... messageFragments) {
|
||||||
println(message);
|
for (Object fragment : messageFragments) {
|
||||||
|
println(fragment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printTypeValue(ConstraintSystemImpl.TypeValue typeValue) {
|
private void printTypeValue(BoundsOwner typeValue) {
|
||||||
for (ConstraintSystemImpl.TypeValue bound : typeValue.getUpperBounds()) {
|
for (BoundsOwner bound : typeValue.getUpperBounds()) {
|
||||||
println(" :< " + bound);
|
println(" :< " + bound);
|
||||||
}
|
}
|
||||||
for (ConstraintSystemImpl.TypeValue bound : typeValue.getLowerBounds()) {
|
for (BoundsOwner bound : typeValue.getLowerBounds()) {
|
||||||
println(" :> " + bound);
|
println(" :> " + bound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package org.jetbrains.jet.lang.resolve.calls.inference;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
import org.jetbrains.jet.lang.types.Variance;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
*/
|
||||||
|
public class TypeValue implements BoundsOwner {
|
||||||
|
private final Set<TypeValue> upperBounds = Sets.newLinkedHashSet();
|
||||||
|
private final Set<TypeValue> lowerBounds = Sets.newLinkedHashSet();
|
||||||
|
|
||||||
|
private final Variance positionVariance;
|
||||||
|
private final TypeParameterDescriptor typeParameterDescriptor; // Null for known types
|
||||||
|
private final JetType originalType;
|
||||||
|
private JetType value; // For an unknown — the value found by constraint resolution, for a known — just it's value
|
||||||
|
|
||||||
|
// Unknown type
|
||||||
|
public TypeValue(@NotNull TypeParameterDescriptor typeParameterDescriptor, @NotNull Variance positionVariance) {
|
||||||
|
this.positionVariance = positionVariance;
|
||||||
|
this.typeParameterDescriptor = typeParameterDescriptor;
|
||||||
|
this.originalType = typeParameterDescriptor.getDefaultType();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Known type
|
||||||
|
public TypeValue(@NotNull JetType knownType) {
|
||||||
|
this.positionVariance = null;
|
||||||
|
this.typeParameterDescriptor = null;
|
||||||
|
this.originalType = knownType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isKnown() {
|
||||||
|
return typeParameterDescriptor == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeParameterDescriptor getTypeParameterDescriptor() {
|
||||||
|
return typeParameterDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public Set<TypeValue> getUpperBounds() {
|
||||||
|
return upperBounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public Set<TypeValue> getLowerBounds() {
|
||||||
|
return lowerBounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public JetType getType() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public JetType getOriginalType() {
|
||||||
|
return originalType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addUpperBound(@NotNull TypeValue bound) {
|
||||||
|
upperBounds.add(bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addLowerBound(@NotNull TypeValue bound) {
|
||||||
|
lowerBounds.add(bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(@NotNull JetType value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasValue() {
|
||||||
|
return value != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +1,41 @@
|
|||||||
package org.jetbrains.jet.lang.types;
|
package org.jetbrains.jet.lang.types;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.SubstitutingScope;
|
import org.jetbrains.jet.lang.resolve.scopes.SubstitutingScope;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public class TypeSubstitutor {
|
public class TypeSubstitutor {
|
||||||
|
|
||||||
|
public static TypeSubstitutor makeConstantSubstitutor(Collection<TypeParameterDescriptor> typeParameterDescriptors, JetType type) {
|
||||||
|
final Set<TypeConstructor> constructors = Sets.newHashSet();
|
||||||
|
for (TypeParameterDescriptor typeParameterDescriptor : typeParameterDescriptors) {
|
||||||
|
constructors.add(typeParameterDescriptor.getTypeConstructor());
|
||||||
|
}
|
||||||
|
final TypeProjection projection = new TypeProjection(type);
|
||||||
|
|
||||||
|
return create(new TypeSubstitution() {
|
||||||
|
@Override
|
||||||
|
public TypeProjection get(TypeConstructor key) {
|
||||||
|
if (constructors.contains(key)) {
|
||||||
|
return projection;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public interface TypeSubstitution {
|
public interface TypeSubstitution {
|
||||||
TypeSubstitution EMPTY = new TypeSubstitution() {
|
TypeSubstitution EMPTY = new TypeSubstitution() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public class JetTypeChecker {
|
|||||||
|
|
||||||
private static class TypeCheckerTypingConstraints implements TypingConstraints {
|
private static class TypeCheckerTypingConstraints implements TypingConstraints {
|
||||||
@Override
|
@Override
|
||||||
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, TypeCheckingProcedure typeCheckingProcedure) {
|
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, @NotNull TypeCheckingProcedure typeCheckingProcedure) {
|
||||||
return typeCheckingProcedure.equalTypes(a, b);
|
return typeCheckingProcedure.equalTypes(a, b);
|
||||||
// return TypeUtils.equalTypes(a, b);
|
// return TypeUtils.equalTypes(a, b);
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ public class JetTypeChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, TypeCheckingProcedure typeCheckingProcedure) {
|
public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeCheckingProcedure typeCheckingProcedure) {
|
||||||
return typeCheckingProcedure.isSubtypeOf(subtype, supertype);
|
return typeCheckingProcedure.isSubtypeOf(subtype, supertype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ import org.jetbrains.jet.lang.types.TypeConstructor;
|
|||||||
* Methods of this class return true to continue type checking and false to fail
|
* Methods of this class return true to continue type checking and false to fail
|
||||||
*/
|
*/
|
||||||
public interface TypingConstraints {
|
public interface TypingConstraints {
|
||||||
boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, TypeCheckingProcedure typeCheckingProcedure);
|
boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, @NotNull TypeCheckingProcedure typeCheckingProcedure);
|
||||||
|
|
||||||
boolean assertEqualTypeConstructors(@NotNull TypeConstructor a, @NotNull TypeConstructor b);
|
boolean assertEqualTypeConstructors(@NotNull TypeConstructor a, @NotNull TypeConstructor b);
|
||||||
|
|
||||||
boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, TypeCheckingProcedure typeCheckingProcedure);
|
boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeCheckingProcedure typeCheckingProcedure);
|
||||||
|
|
||||||
boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype);
|
boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext;
|
|||||||
import org.jetbrains.jet.lang.resolve.calls.ResolutionDebugInfo;
|
import org.jetbrains.jet.lang.resolve.calls.ResolutionDebugInfo;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedValueArgument;
|
import org.jetbrains.jet.lang.resolve.calls.ResolvedValueArgument;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.inference.BoundsOwner;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl;
|
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
@@ -190,9 +191,9 @@ public class ResolveToolwindow extends JPanel {
|
|||||||
result.append("Log: \n").append(log).append(bar);
|
result.append("Log: \n").append(log).append(bar);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<JetType, ConstraintSystemImpl.TypeValue> knowns = debugInfo.get(BOUNDS_FOR_KNOWNS);
|
Map<JetType, BoundsOwner> knowns = debugInfo.get(BOUNDS_FOR_KNOWNS);
|
||||||
renderMap(knowns, result);
|
renderMap(knowns, result);
|
||||||
Map<TypeParameterDescriptor, ConstraintSystemImpl.TypeValue> unknowns = debugInfo.get(BOUNDS_FOR_UNKNOWNS);
|
Map<TypeParameterDescriptor, BoundsOwner> unknowns = debugInfo.get(BOUNDS_FOR_UNKNOWNS);
|
||||||
renderMap(unknowns, result);
|
renderMap(unknowns, result);
|
||||||
|
|
||||||
result.append(bar);
|
result.append(bar);
|
||||||
@@ -205,17 +206,17 @@ public class ResolveToolwindow extends JPanel {
|
|||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private <K> void renderMap(Map<K, ConstraintSystemImpl.TypeValue> map, StringBuilder builder) {
|
private <K> void renderMap(Map<K, BoundsOwner> map, StringBuilder builder) {
|
||||||
if (map == null) return;
|
if (map == null) return;
|
||||||
|
|
||||||
for (Map.Entry<K, ConstraintSystemImpl.TypeValue> entry : map.entrySet()) {
|
for (Map.Entry<K, BoundsOwner> entry : map.entrySet()) {
|
||||||
K key = entry.getKey();
|
K key = entry.getKey();
|
||||||
ConstraintSystemImpl.TypeValue typeValue = entry.getValue();
|
BoundsOwner typeValue = entry.getValue();
|
||||||
builder.append("Bounds for ").append(key).append("\n");
|
builder.append("Bounds for ").append(key).append("\n");
|
||||||
for (ConstraintSystemImpl.TypeValue bound : typeValue.getLowerBounds()) {
|
for (BoundsOwner bound : typeValue.getLowerBounds()) {
|
||||||
builder.append(" >: ").append(bound).append("\n");
|
builder.append(" >: ").append(bound).append("\n");
|
||||||
}
|
}
|
||||||
for (ConstraintSystemImpl.TypeValue bound : typeValue.getUpperBounds()) {
|
for (BoundsOwner bound : typeValue.getUpperBounds()) {
|
||||||
builder.append(" <: ").append(bound).append("\n");
|
builder.append(" <: ").append(bound).append("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user