refactoring: moved 'getValue', 'getValues' methods to TypeConstraints

This commit is contained in:
Svetlana Isakova
2013-09-17 15:51:33 +04:00
parent eb513438c9
commit 2d65186574
7 changed files with 170 additions and 158 deletions
@@ -31,6 +31,7 @@ import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintsUtil;
import org.jetbrains.jet.lang.resolve.calls.inference.InferenceErrorData;
import org.jetbrains.jet.lang.resolve.calls.inference.TypeConstraints;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
@@ -277,7 +278,7 @@ public class Renderers {
.table(newTable().
descriptor(inferenceErrorData.descriptor));
JetType inferredValueForTypeParameter = ConstraintsUtil.getValue(inferenceErrorData.constraintSystem.getTypeConstraints(typeParameterDescriptor));
JetType inferredValueForTypeParameter = inferenceErrorData.constraintSystem.getTypeConstraints(typeParameterDescriptor).getValue();
assert inferredValueForTypeParameter != null;
JetType upperBound = typeParameterDescriptor.getUpperBoundsAsType();
JetType upperBoundWithSubstitutedInferredTypes = inferenceErrorData.constraintSystem.getResultingSubstitutor().substitute(upperBound, Variance.INVARIANT);
@@ -30,6 +30,7 @@ import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext;
import org.jetbrains.jet.lang.resolve.calls.context.CallResolutionContext;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintsUtil;
import org.jetbrains.jet.lang.resolve.calls.inference.TypeConstraints;
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.model.ResolvedValueArgument;
@@ -115,7 +116,7 @@ public class CallResolverUtil {
if (returnType == null) return false;
for (TypeParameterDescriptor typeVariable : constraintSystem.getTypeVariables()) {
JetType inferredValueForTypeVariable = ConstraintsUtil.getValue(constraintSystem.getTypeConstraints(typeVariable));
JetType inferredValueForTypeVariable = constraintSystem.getTypeConstraints(typeVariable).getValue();
if (inferredValueForTypeVariable == null) {
if (TypeUtils.dependsOnTypeParameters(returnType, Collections.singleton(typeVariable))) {
return true;
@@ -64,7 +64,7 @@ public interface ConstraintSystem {
* Returns the resulting type constraints of solving the constraint system for specific type variable. <p/>
* Returns null if the type variable was not registered.
*/
@Nullable
@NotNull
TypeConstraints getTypeConstraints(@NotNull TypeParameterDescriptor typeVariable);
/**
@@ -72,7 +72,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
public boolean hasConflictingConstraints() {
for (TypeParameterDescriptor typeParameter : typeParameterConstraints.keySet()) {
TypeConstraints typeConstraints = getTypeConstraints(typeParameter);
if (typeConstraints != null && ConstraintsUtil.getValues(typeConstraints).size() > 1) return true;
if (typeConstraints.getValues().size() > 1) return true;
}
return false;
}
@@ -133,11 +133,11 @@ public class ConstraintSystemImpl implements ConstraintSystem {
if (declarationDescriptor instanceof TypeParameterDescriptor) {
TypeParameterDescriptor descriptor = (TypeParameterDescriptor) declarationDescriptor;
JetType value = ConstraintsUtil.getValue(getTypeConstraints(descriptor));
if (value != null && !TypeUtils.equalsOrContainsAsArgument(value, DONT_CARE)) {
return new TypeProjection(value);
}
if (typeParameterConstraints.containsKey(descriptor)) {
JetType value = getTypeConstraints(descriptor).getValue();
if (value != null && !TypeUtils.equalsOrContainsAsArgument(value, DONT_CARE)) {
return new TypeProjection(value);
}
return defaultTypeProjection;
}
}
@@ -363,9 +363,11 @@ public class ConstraintSystemImpl implements ConstraintSystem {
}
@Override
@Nullable
@NotNull
public TypeConstraints getTypeConstraints(@NotNull TypeParameterDescriptor typeVariable) {
return typeParameterConstraints.get(typeVariable);
TypeConstraintsImpl typeConstraints = typeParameterConstraints.get(typeVariable);
assert typeConstraints != null : "TypeParameterDescriptor is not a type variable for constraint system: " + typeVariable;
return typeConstraints;
}
@Nullable
@@ -19,8 +19,6 @@ package org.jetbrains.jet.lang.resolve.calls.inference;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.openapi.util.Pair;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
@@ -30,147 +28,11 @@ import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import java.util.*;
public class ConstraintsUtil {
@NotNull
public static Set<JetType> getValues(@Nullable TypeConstraints typeConstraints) {
Set<JetType> values = Sets.newLinkedHashSet();
if (typeConstraints == null || typeConstraints.isEmpty()) {
return values;
}
TypeConstraints typeConstraintsWithoutErrorTypes = filterNotContainingErrorType(typeConstraints, values);
Collection<JetType> exactBounds = typeConstraintsWithoutErrorTypes.getExactBounds();
if (exactBounds.size() == 1) {
JetType exactBound = exactBounds.iterator().next();
if (trySuggestion(exactBound, typeConstraints)) {
return Collections.singleton(exactBound);
}
}
values.addAll(exactBounds);
Pair<Collection<JetType>, Collection<JetType>> pair =
TypeUtils.filterNumberTypes(typeConstraintsWithoutErrorTypes.getLowerBounds());
Collection<JetType> generalLowerBounds = pair.getFirst();
Collection<JetType> numberLowerBounds = pair.getSecond();
JetType superTypeOfLowerBounds = commonSupertype(generalLowerBounds);
if (trySuggestion(superTypeOfLowerBounds, typeConstraints)) {
return Collections.singleton(superTypeOfLowerBounds);
}
ContainerUtil.addIfNotNull(superTypeOfLowerBounds, values);
Collection<JetType> upperBounds = typeConstraintsWithoutErrorTypes.getUpperBounds();
for (JetType upperBound : upperBounds) {
if (trySuggestion(upperBound, typeConstraints)) {
return Collections.singleton(upperBound);
}
}
//todo
//fun <T> foo(t: T, consumer: Consumer<T>): T
//foo(1, c: Consumer<Any>) - infer Int, not Any here
values.addAll(typeConstraintsWithoutErrorTypes.getUpperBounds());
JetType superTypeOfNumberLowerBounds = commonSupertypeForNumberTypes(numberLowerBounds);
if (trySuggestion(superTypeOfNumberLowerBounds, typeConstraints)) {
return Collections.singleton(superTypeOfNumberLowerBounds);
}
ContainerUtil.addIfNotNull(superTypeOfNumberLowerBounds, values);
if (superTypeOfLowerBounds != null && superTypeOfNumberLowerBounds != null) {
JetType superTypeOfAllLowerBounds = commonSupertype(Lists.newArrayList(superTypeOfLowerBounds, superTypeOfNumberLowerBounds));
if (trySuggestion(superTypeOfAllLowerBounds, typeConstraints)) {
return Collections.singleton(superTypeOfAllLowerBounds);
}
}
return values;
}
@Nullable
private static JetType commonSupertype(@NotNull Collection<JetType> lowerBounds) {
if (lowerBounds.isEmpty()) return null;
if (lowerBounds.size() == 1) {
JetType type = lowerBounds.iterator().next();
if (type.getConstructor() instanceof IntersectionTypeConstructor) {
return commonSupertype(type.getConstructor().getSupertypes());
}
}
return CommonSupertypes.commonSupertype(lowerBounds);
}
@Nullable
private static JetType commonSupertypeForNumberTypes(@NotNull Collection<JetType> numberLowerBounds) {
if (numberLowerBounds.isEmpty()) return null;
return TypeUtils.commonSupertypeForNumberTypes(numberLowerBounds);
}
private static boolean trySuggestion(
@Nullable JetType suggestion,
@NotNull TypeConstraints typeConstraints
) {
if (suggestion == null) return false;
if (!suggestion.getConstructor().isDenotable()) return false;
if (typeConstraints.getExactBounds().size() > 1) return false;
for (JetType exactBound : typeConstraints.getExactBounds()) {
if (!JetTypeChecker.INSTANCE.equalTypes(exactBound, suggestion)) {
return false;
}
}
for (JetType lowerBound : typeConstraints.getLowerBounds()) {
if (!JetTypeChecker.INSTANCE.isSubtypeOf(lowerBound, suggestion)) {
return false;
}
}
for (JetType upperBound : typeConstraints.getUpperBounds()) {
if (!JetTypeChecker.INSTANCE.isSubtypeOf(suggestion, upperBound)) {
return false;
}
}
return true;
}
@NotNull
private static TypeConstraints filterNotContainingErrorType(
@NotNull TypeConstraints typeConstraints,
@NotNull Collection<JetType> values
) {
TypeConstraintsImpl typeConstraintsWithoutErrorType = new TypeConstraintsImpl(typeConstraints.getVarianceOfPosition());
Collection<Pair<TypeConstraintsImpl.BoundKind, JetType>> allBounds = ((TypeConstraintsImpl) typeConstraints).getAllBounds();
for (Pair<TypeConstraintsImpl.BoundKind, JetType> pair : allBounds) {
TypeConstraintsImpl.BoundKind boundKind = pair.getFirst();
JetType type = pair.getSecond();
if (ErrorUtils.containsErrorType(type)) {
values.add(type);
}
else if (type != null) {
typeConstraintsWithoutErrorType.addBound(boundKind, type);
}
}
return typeConstraintsWithoutErrorType;
}
@Nullable
public static JetType getValue(@Nullable TypeConstraints typeConstraints) {
//todo all checks
//todo variance dependance
if (typeConstraints == null) {
//todo assert typeConstraints != null;
return null;
}
Set<JetType> values = getValues(typeConstraints);
if (values.size() == 1) {
return values.iterator().next();
}
return null;
}
@Nullable
public static TypeParameterDescriptor getFirstConflictingParameter(@NotNull ConstraintSystem constraintSystem) {
for (TypeParameterDescriptor typeParameter : constraintSystem.getTypeVariables()) {
TypeConstraints constraints = constraintSystem.getTypeConstraints(typeParameter);
if (getValues(constraints).size() > 1) {
if (constraints.getValues().size() > 1) {
return typeParameter;
}
}
@@ -182,7 +44,7 @@ public class ConstraintsUtil {
TypeParameterDescriptor firstConflictingParameter = getFirstConflictingParameter(constraintSystem);
if (firstConflictingParameter == null) return Collections.emptyList();
Collection<JetType> conflictingTypes = getValues(constraintSystem.getTypeConstraints(firstConflictingParameter));
Collection<JetType> conflictingTypes = constraintSystem.getTypeConstraints(firstConflictingParameter).getValues();
ArrayList<Map<TypeConstructor, TypeProjection>> substitutionContexts = Lists.newArrayList();
for (JetType type : conflictingTypes) {
@@ -209,8 +71,7 @@ public class ConstraintsUtil {
@NotNull
public static JetType getSafeValue(@NotNull ConstraintSystem constraintSystem, @NotNull TypeParameterDescriptor typeParameter) {
TypeConstraints constraints = constraintSystem.getTypeConstraints(typeParameter);
JetType type = getValue(constraints);
JetType type = constraintSystem.getTypeConstraints(typeParameter).getValue();
if (type != null) {
return type;
}
@@ -223,9 +84,7 @@ public class ConstraintsUtil {
@NotNull TypeParameterDescriptor typeParameter,
boolean substituteOtherTypeParametersInBound
) {
TypeConstraints typeConstraints = constraintSystem.getTypeConstraints(typeParameter);
assert typeConstraints != null;
JetType type = getValue(typeConstraints);
JetType type = constraintSystem.getTypeConstraints(typeParameter).getValue();
if (type == null) return true;
for (JetType upperBound : typeParameter.getUpperBounds()) {
if (!substituteOtherTypeParametersInBound && TypeUtils.dependsOnTypeParameters(upperBound, constraintSystem.getTypeVariables())) {
@@ -38,4 +38,10 @@ public interface TypeConstraints {
Variance getVarianceOfPosition();
boolean isEmpty();
@Nullable
JetType getValue();
@NotNull
Collection<JetType> getValues();
}
@@ -19,11 +19,15 @@ package org.jetbrains.jet.lang.resolve.calls.inference;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.intellij.openapi.util.Pair;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Predicate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.Variance;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
public class TypeConstraintsImpl implements TypeConstraints {
@@ -32,6 +36,8 @@ public class TypeConstraintsImpl implements TypeConstraints {
private final Set<JetType> lowerBounds = Sets.newLinkedHashSet();
private final Set<JetType> exactBounds = Sets.newLinkedHashSet();
private Collection<JetType> resultValues;
public TypeConstraintsImpl(Variance varianceOfPosition) {
this.varianceOfPosition = varianceOfPosition;
}
@@ -43,6 +49,7 @@ public class TypeConstraintsImpl implements TypeConstraints {
}
public void addBound(@NotNull BoundKind boundKind, @NotNull JetType type) {
resultValues = null;
switch (boundKind) {
case LOWER_BOUND:
lowerBounds.add(type);
@@ -83,6 +90,7 @@ public class TypeConstraintsImpl implements TypeConstraints {
typeConstraints.upperBounds.addAll(upperBounds);
typeConstraints.lowerBounds.addAll(lowerBounds);
typeConstraints.exactBounds.addAll(exactBounds);
typeConstraints.resultValues = resultValues;
return typeConstraints;
}
@@ -90,7 +98,7 @@ public class TypeConstraintsImpl implements TypeConstraints {
LOWER_BOUND, UPPER_BOUND, EXACT_BOUND
}
public Collection<Pair<BoundKind, JetType>> getAllBounds() {
private Collection<Pair<BoundKind, JetType>> getAllBounds() {
Collection<Pair<BoundKind, JetType>> result = Lists.newArrayList();
for (JetType exactBound : exactBounds) {
result.add(Pair.create(BoundKind.EXACT_BOUND, exactBound));
@@ -103,4 +111,139 @@ public class TypeConstraintsImpl implements TypeConstraints {
}
return result;
}
@Nullable
@Override
public JetType getValue() {
Collection<JetType> values = getValues();
if (values.size() == 1) {
return values.iterator().next();
}
return null;
}
@NotNull
@Override
public Collection<JetType> getValues() {
if (resultValues == null) {
resultValues = computeValues();
}
return resultValues;
}
private Collection<JetType> computeValues() {
Set<JetType> values = Sets.newLinkedHashSet();
if (isEmpty()) {
return values;
}
TypeConstraints withoutErrorTypes = filterNotContainingErrorType(values);
Collection<JetType> exactBounds = withoutErrorTypes.getExactBounds();
if (exactBounds.size() == 1) {
JetType exactBound = exactBounds.iterator().next();
if (trySuggestion(exactBound)) {
return Collections.singleton(exactBound);
}
}
values.addAll(exactBounds);
Pair<Collection<JetType>, Collection<JetType>> pair =
TypeUtils.filterNumberTypes(withoutErrorTypes.getLowerBounds());
Collection<JetType> generalLowerBounds = pair.getFirst();
Collection<JetType> numberLowerBounds = pair.getSecond();
JetType superTypeOfLowerBounds = commonSupertype(generalLowerBounds);
if (trySuggestion(superTypeOfLowerBounds)) {
return Collections.singleton(superTypeOfLowerBounds);
}
ContainerUtil.addIfNotNull(superTypeOfLowerBounds, values);
Collection<JetType> upperBounds = withoutErrorTypes.getUpperBounds();
for (JetType upperBound : upperBounds) {
if (trySuggestion(upperBound)) {
return Collections.singleton(upperBound);
}
}
//todo
//fun <T> foo(t: T, consumer: Consumer<T>): T
//foo(1, c: Consumer<Any>) - infer Int, not Any here
values.addAll(withoutErrorTypes.getUpperBounds());
JetType superTypeOfNumberLowerBounds = commonSupertypeForNumberTypes(numberLowerBounds);
if (trySuggestion(superTypeOfNumberLowerBounds)) {
return Collections.singleton(superTypeOfNumberLowerBounds);
}
ContainerUtil.addIfNotNull(superTypeOfNumberLowerBounds, values);
if (superTypeOfLowerBounds != null && superTypeOfNumberLowerBounds != null) {
JetType superTypeOfAllLowerBounds = commonSupertype(Lists.newArrayList(superTypeOfLowerBounds, superTypeOfNumberLowerBounds));
if (trySuggestion(superTypeOfAllLowerBounds)) {
return Collections.singleton(superTypeOfAllLowerBounds);
}
}
return values;
}
private boolean trySuggestion(
@Nullable JetType suggestion
) {
if (suggestion == null) return false;
if (!suggestion.getConstructor().isDenotable()) return false;
if (getExactBounds().size() > 1) return false;
for (JetType exactBound : getExactBounds()) {
if (!JetTypeChecker.INSTANCE.equalTypes(exactBound, suggestion)) {
return false;
}
}
for (JetType lowerBound : getLowerBounds()) {
if (!JetTypeChecker.INSTANCE.isSubtypeOf(lowerBound, suggestion)) {
return false;
}
}
for (JetType upperBound : getUpperBounds()) {
if (!JetTypeChecker.INSTANCE.isSubtypeOf(suggestion, upperBound)) {
return false;
}
}
return true;
}
@NotNull
private TypeConstraints filterNotContainingErrorType(
@NotNull Collection<JetType> values
) {
TypeConstraintsImpl typeConstraintsWithoutErrorType = new TypeConstraintsImpl(getVarianceOfPosition());
Collection<Pair<TypeConstraintsImpl.BoundKind, JetType>> allBounds = getAllBounds();
for (Pair<TypeConstraintsImpl.BoundKind, JetType> pair : allBounds) {
TypeConstraintsImpl.BoundKind boundKind = pair.getFirst();
JetType type = pair.getSecond();
if (ErrorUtils.containsErrorType(type)) {
values.add(type);
}
else if (type != null) {
typeConstraintsWithoutErrorType.addBound(boundKind, type);
}
}
return typeConstraintsWithoutErrorType;
}
@Nullable
private static JetType commonSupertype(@NotNull Collection<JetType> lowerBounds) {
if (lowerBounds.isEmpty()) return null;
if (lowerBounds.size() == 1) {
JetType type = lowerBounds.iterator().next();
if (type.getConstructor() instanceof IntersectionTypeConstructor) {
return commonSupertype(type.getConstructor().getSupertypes());
}
}
return CommonSupertypes.commonSupertype(lowerBounds);
}
@Nullable
private static JetType commonSupertypeForNumberTypes(@NotNull Collection<JetType> numberLowerBounds) {
if (numberLowerBounds.isEmpty()) return null;
return TypeUtils.commonSupertypeForNumberTypes(numberLowerBounds);
}
}