refactoring: moved 'getValue', 'getValues' methods to TypeConstraints
This commit is contained in:
@@ -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.ConstraintPosition;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintsUtil;
|
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.InferenceErrorData;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.inference.TypeConstraints;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.lang.types.TypeSubstitutor;
|
import org.jetbrains.jet.lang.types.TypeSubstitutor;
|
||||||
@@ -277,7 +278,7 @@ public class Renderers {
|
|||||||
.table(newTable().
|
.table(newTable().
|
||||||
descriptor(inferenceErrorData.descriptor));
|
descriptor(inferenceErrorData.descriptor));
|
||||||
|
|
||||||
JetType inferredValueForTypeParameter = ConstraintsUtil.getValue(inferenceErrorData.constraintSystem.getTypeConstraints(typeParameterDescriptor));
|
JetType inferredValueForTypeParameter = inferenceErrorData.constraintSystem.getTypeConstraints(typeParameterDescriptor).getValue();
|
||||||
assert inferredValueForTypeParameter != null;
|
assert inferredValueForTypeParameter != null;
|
||||||
JetType upperBound = typeParameterDescriptor.getUpperBoundsAsType();
|
JetType upperBound = typeParameterDescriptor.getUpperBoundsAsType();
|
||||||
JetType upperBoundWithSubstitutedInferredTypes = inferenceErrorData.constraintSystem.getResultingSubstitutor().substitute(upperBound, Variance.INVARIANT);
|
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.context.CallResolutionContext;
|
||||||
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.ConstraintsUtil;
|
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.ResolvedCallImpl;
|
||||||
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.ResolvedValueArgument;
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
|
||||||
@@ -115,7 +116,7 @@ public class CallResolverUtil {
|
|||||||
if (returnType == null) return false;
|
if (returnType == null) return false;
|
||||||
|
|
||||||
for (TypeParameterDescriptor typeVariable : constraintSystem.getTypeVariables()) {
|
for (TypeParameterDescriptor typeVariable : constraintSystem.getTypeVariables()) {
|
||||||
JetType inferredValueForTypeVariable = ConstraintsUtil.getValue(constraintSystem.getTypeConstraints(typeVariable));
|
JetType inferredValueForTypeVariable = constraintSystem.getTypeConstraints(typeVariable).getValue();
|
||||||
if (inferredValueForTypeVariable == null) {
|
if (inferredValueForTypeVariable == null) {
|
||||||
if (TypeUtils.dependsOnTypeParameters(returnType, Collections.singleton(typeVariable))) {
|
if (TypeUtils.dependsOnTypeParameters(returnType, Collections.singleton(typeVariable))) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
+1
-1
@@ -64,7 +64,7 @@ public interface ConstraintSystem {
|
|||||||
* Returns the resulting type constraints of solving the constraint system for specific type variable. <p/>
|
* Returns the resulting type constraints of solving the constraint system for specific type variable. <p/>
|
||||||
* Returns null if the type variable was not registered.
|
* Returns null if the type variable was not registered.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@NotNull
|
||||||
TypeConstraints getTypeConstraints(@NotNull TypeParameterDescriptor typeVariable);
|
TypeConstraints getTypeConstraints(@NotNull TypeParameterDescriptor typeVariable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+9
-7
@@ -72,7 +72,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
public boolean hasConflictingConstraints() {
|
public boolean hasConflictingConstraints() {
|
||||||
for (TypeParameterDescriptor typeParameter : typeParameterConstraints.keySet()) {
|
for (TypeParameterDescriptor typeParameter : typeParameterConstraints.keySet()) {
|
||||||
TypeConstraints typeConstraints = getTypeConstraints(typeParameter);
|
TypeConstraints typeConstraints = getTypeConstraints(typeParameter);
|
||||||
if (typeConstraints != null && ConstraintsUtil.getValues(typeConstraints).size() > 1) return true;
|
if (typeConstraints.getValues().size() > 1) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -133,11 +133,11 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
if (declarationDescriptor instanceof TypeParameterDescriptor) {
|
if (declarationDescriptor instanceof TypeParameterDescriptor) {
|
||||||
TypeParameterDescriptor descriptor = (TypeParameterDescriptor) declarationDescriptor;
|
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)) {
|
if (typeParameterConstraints.containsKey(descriptor)) {
|
||||||
|
JetType value = getTypeConstraints(descriptor).getValue();
|
||||||
|
if (value != null && !TypeUtils.equalsOrContainsAsArgument(value, DONT_CARE)) {
|
||||||
|
return new TypeProjection(value);
|
||||||
|
}
|
||||||
return defaultTypeProjection;
|
return defaultTypeProjection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -363,9 +363,11 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@NotNull
|
||||||
public TypeConstraints getTypeConstraints(@NotNull TypeParameterDescriptor typeVariable) {
|
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
|
@Nullable
|
||||||
|
|||||||
+4
-145
@@ -19,8 +19,6 @@ package org.jetbrains.jet.lang.resolve.calls.inference;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Sets;
|
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.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;
|
||||||
@@ -30,147 +28,11 @@ import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class ConstraintsUtil {
|
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
|
@Nullable
|
||||||
public static TypeParameterDescriptor getFirstConflictingParameter(@NotNull ConstraintSystem constraintSystem) {
|
public static TypeParameterDescriptor getFirstConflictingParameter(@NotNull ConstraintSystem constraintSystem) {
|
||||||
for (TypeParameterDescriptor typeParameter : constraintSystem.getTypeVariables()) {
|
for (TypeParameterDescriptor typeParameter : constraintSystem.getTypeVariables()) {
|
||||||
TypeConstraints constraints = constraintSystem.getTypeConstraints(typeParameter);
|
TypeConstraints constraints = constraintSystem.getTypeConstraints(typeParameter);
|
||||||
if (getValues(constraints).size() > 1) {
|
if (constraints.getValues().size() > 1) {
|
||||||
return typeParameter;
|
return typeParameter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,7 +44,7 @@ public class ConstraintsUtil {
|
|||||||
TypeParameterDescriptor firstConflictingParameter = getFirstConflictingParameter(constraintSystem);
|
TypeParameterDescriptor firstConflictingParameter = getFirstConflictingParameter(constraintSystem);
|
||||||
if (firstConflictingParameter == null) return Collections.emptyList();
|
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();
|
ArrayList<Map<TypeConstructor, TypeProjection>> substitutionContexts = Lists.newArrayList();
|
||||||
for (JetType type : conflictingTypes) {
|
for (JetType type : conflictingTypes) {
|
||||||
@@ -209,8 +71,7 @@ public class ConstraintsUtil {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JetType getSafeValue(@NotNull ConstraintSystem constraintSystem, @NotNull TypeParameterDescriptor typeParameter) {
|
public static JetType getSafeValue(@NotNull ConstraintSystem constraintSystem, @NotNull TypeParameterDescriptor typeParameter) {
|
||||||
TypeConstraints constraints = constraintSystem.getTypeConstraints(typeParameter);
|
JetType type = constraintSystem.getTypeConstraints(typeParameter).getValue();
|
||||||
JetType type = getValue(constraints);
|
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
@@ -223,9 +84,7 @@ public class ConstraintsUtil {
|
|||||||
@NotNull TypeParameterDescriptor typeParameter,
|
@NotNull TypeParameterDescriptor typeParameter,
|
||||||
boolean substituteOtherTypeParametersInBound
|
boolean substituteOtherTypeParametersInBound
|
||||||
) {
|
) {
|
||||||
TypeConstraints typeConstraints = constraintSystem.getTypeConstraints(typeParameter);
|
JetType type = constraintSystem.getTypeConstraints(typeParameter).getValue();
|
||||||
assert typeConstraints != null;
|
|
||||||
JetType type = getValue(typeConstraints);
|
|
||||||
if (type == null) return true;
|
if (type == null) return true;
|
||||||
for (JetType upperBound : typeParameter.getUpperBounds()) {
|
for (JetType upperBound : typeParameter.getUpperBounds()) {
|
||||||
if (!substituteOtherTypeParametersInBound && TypeUtils.dependsOnTypeParameters(upperBound, constraintSystem.getTypeVariables())) {
|
if (!substituteOtherTypeParametersInBound && TypeUtils.dependsOnTypeParameters(upperBound, constraintSystem.getTypeVariables())) {
|
||||||
|
|||||||
+6
@@ -38,4 +38,10 @@ public interface TypeConstraints {
|
|||||||
Variance getVarianceOfPosition();
|
Variance getVarianceOfPosition();
|
||||||
|
|
||||||
boolean isEmpty();
|
boolean isEmpty();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
JetType getValue();
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
Collection<JetType> getValues();
|
||||||
}
|
}
|
||||||
|
|||||||
+146
-3
@@ -19,11 +19,15 @@ package org.jetbrains.jet.lang.resolve.calls.inference;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.intellij.openapi.util.Pair;
|
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.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.types.Variance;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
|
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class TypeConstraintsImpl implements TypeConstraints {
|
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> lowerBounds = Sets.newLinkedHashSet();
|
||||||
private final Set<JetType> exactBounds = Sets.newLinkedHashSet();
|
private final Set<JetType> exactBounds = Sets.newLinkedHashSet();
|
||||||
|
|
||||||
|
private Collection<JetType> resultValues;
|
||||||
|
|
||||||
public TypeConstraintsImpl(Variance varianceOfPosition) {
|
public TypeConstraintsImpl(Variance varianceOfPosition) {
|
||||||
this.varianceOfPosition = varianceOfPosition;
|
this.varianceOfPosition = varianceOfPosition;
|
||||||
}
|
}
|
||||||
@@ -43,6 +49,7 @@ public class TypeConstraintsImpl implements TypeConstraints {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addBound(@NotNull BoundKind boundKind, @NotNull JetType type) {
|
public void addBound(@NotNull BoundKind boundKind, @NotNull JetType type) {
|
||||||
|
resultValues = null;
|
||||||
switch (boundKind) {
|
switch (boundKind) {
|
||||||
case LOWER_BOUND:
|
case LOWER_BOUND:
|
||||||
lowerBounds.add(type);
|
lowerBounds.add(type);
|
||||||
@@ -83,6 +90,7 @@ public class TypeConstraintsImpl implements TypeConstraints {
|
|||||||
typeConstraints.upperBounds.addAll(upperBounds);
|
typeConstraints.upperBounds.addAll(upperBounds);
|
||||||
typeConstraints.lowerBounds.addAll(lowerBounds);
|
typeConstraints.lowerBounds.addAll(lowerBounds);
|
||||||
typeConstraints.exactBounds.addAll(exactBounds);
|
typeConstraints.exactBounds.addAll(exactBounds);
|
||||||
|
typeConstraints.resultValues = resultValues;
|
||||||
return typeConstraints;
|
return typeConstraints;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +98,7 @@ public class TypeConstraintsImpl implements TypeConstraints {
|
|||||||
LOWER_BOUND, UPPER_BOUND, EXACT_BOUND
|
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();
|
Collection<Pair<BoundKind, JetType>> result = Lists.newArrayList();
|
||||||
for (JetType exactBound : exactBounds) {
|
for (JetType exactBound : exactBounds) {
|
||||||
result.add(Pair.create(BoundKind.EXACT_BOUND, exactBound));
|
result.add(Pair.create(BoundKind.EXACT_BOUND, exactBound));
|
||||||
@@ -103,4 +111,139 @@ public class TypeConstraintsImpl implements TypeConstraints {
|
|||||||
}
|
}
|
||||||
return result;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user