Merge pull request #15128 from rudkx/handle-relational-constraints-in-bindings
Begin refactoring type variable binding code.
diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp
index 2248a6c..0af0aee 100644
--- a/lib/Sema/CSBindings.cpp
+++ b/lib/Sema/CSBindings.cpp
@@ -197,6 +197,135 @@
Bindings.push_back(std::move(binding));
}
+Optional<ConstraintSystem::PotentialBinding>
+ConstraintSystem::getPotentialBindingForRelationalConstraint(
+ PotentialBindings &result, Constraint *constraint,
+ bool &hasDependentMemberRelationalConstraints,
+ bool &hasNonDependentMemberRelationalConstraints,
+ bool &addOptionalSupertypeBindings) {
+ assert(constraint->getClassification() ==
+ ConstraintClassification::Relational &&
+ "only relational constraints handled here");
+
+ auto *typeVar = result.TypeVar;
+
+ // Record constraint which contributes to the
+ // finding of potential bindings.
+ result.Sources.insert(constraint);
+
+ auto first = simplifyType(constraint->getFirstType());
+ auto second = simplifyType(constraint->getSecondType());
+
+ if (first->is<TypeVariableType>() && first->isEqual(second))
+ return None;
+
+ Type type;
+ AllowedBindingKind kind;
+ if (first->getAs<TypeVariableType>() == typeVar) {
+ // Upper bound for this type variable.
+ type = second;
+ kind = AllowedBindingKind::Subtypes;
+ } else if (second->getAs<TypeVariableType>() == typeVar) {
+ // Lower bound for this type variable.
+ type = first;
+ kind = AllowedBindingKind::Supertypes;
+ } else {
+ // Can't infer anything.
+ if (result.InvolvesTypeVariables)
+ return None;
+
+ // Check whether both this type and another type variable are
+ // inferable.
+ SmallPtrSet<TypeVariableType *, 4> typeVars;
+ findInferableTypeVars(first, typeVars);
+ findInferableTypeVars(second, typeVars);
+ if (typeVars.size() > 1 && typeVars.count(typeVar))
+ result.InvolvesTypeVariables = true;
+ return None;
+ }
+
+ // Do not attempt to bind to ErrorType.
+ if (type->hasError())
+ return None;
+
+ // If the source of the binding is 'OptionalObject' constraint
+ // and type variable is on the left-hand side, that means
+ // that it _has_ to be of optional type, since the right-hand
+ // side of the constraint is object type of the optional.
+ if (constraint->getKind() == ConstraintKind::OptionalObject &&
+ kind == AllowedBindingKind::Subtypes) {
+ type = OptionalType::get(type);
+ }
+
+ // If the type we'd be binding to is a dependent member, don't try to
+ // resolve this type variable yet.
+ if (type->is<DependentMemberType>()) {
+ if (!ConstraintSystem::typeVarOccursInType(typeVar, type,
+ &result.InvolvesTypeVariables)) {
+ hasDependentMemberRelationalConstraints = true;
+ }
+ return None;
+ }
+ hasNonDependentMemberRelationalConstraints = true;
+
+ // Check whether we can perform this binding.
+ // FIXME: this has a super-inefficient extraneous simplifyType() in it.
+ bool isNilLiteral = false;
+ bool *isNilLiteralPtr = nullptr;
+ if (!addOptionalSupertypeBindings && kind == AllowedBindingKind::Supertypes)
+ isNilLiteralPtr = &isNilLiteral;
+ if (auto boundType = checkTypeOfBinding(typeVar, type, isNilLiteralPtr)) {
+ type = *boundType;
+ if (type->hasTypeVariable())
+ result.InvolvesTypeVariables = true;
+ } else {
+ // If the bound is a 'nil' literal type, add optional supertype bindings.
+ if (isNilLiteral) {
+ addOptionalSupertypeBindings = true;
+ return None;
+ }
+
+ result.InvolvesTypeVariables = true;
+ return None;
+ }
+
+ // Don't deduce autoclosure types or single-element, non-variadic
+ // tuples.
+ if (shouldBindToValueType(constraint)) {
+ if (auto funcTy = type->getAs<FunctionType>()) {
+ if (funcTy->isAutoClosure())
+ type = funcTy->getResult();
+ }
+
+ type = type->getWithoutImmediateLabel();
+ }
+
+ // Make sure we aren't trying to equate type variables with different
+ // lvalue-binding rules.
+ if (auto otherTypeVar =
+ type->lookThroughAllOptionalTypes()->getAs<TypeVariableType>()) {
+ if (typeVar->getImpl().canBindToLValue() !=
+ otherTypeVar->getImpl().canBindToLValue())
+ return None;
+ }
+
+ // BindParam constraints are not reflexive and must be treated specially.
+ if (constraint->getKind() == ConstraintKind::BindParam) {
+ if (kind == AllowedBindingKind::Subtypes) {
+ if (auto *lvt = type->getAs<LValueType>()) {
+ type = InOutType::get(lvt->getObjectType());
+ }
+ } else if (kind == AllowedBindingKind::Supertypes) {
+ if (auto *iot = type->getAs<InOutType>()) {
+ type = LValueType::get(iot->getObjectType());
+ }
+ }
+ kind = AllowedBindingKind::Exact;
+ }
+
+ return PotentialBinding{type, kind, constraint->getKind()};
+}
+
/// \brief Retrieve the set of potential type bindings for the given
/// representative type variable, along with flags indicating whether
/// those types should be opened.
@@ -238,9 +367,19 @@
case ConstraintKind::ArgumentTupleConversion:
case ConstraintKind::OperatorArgumentTupleConversion:
case ConstraintKind::OperatorArgumentConversion:
- case ConstraintKind::OptionalObject:
- // Relational constraints: break out to look for types above/below.
+ case ConstraintKind::OptionalObject: {
+ auto binding = getPotentialBindingForRelationalConstraint(
+ result, constraint, hasDependentMemberRelationalConstraints,
+ hasNonDependentMemberRelationalConstraints,
+ addOptionalSupertypeBindings);
+ if (!binding)
+ break;
+
+ auto type = binding->BindingType;
+ if (exactTypes.insert(type->getCanonicalType()).second)
+ result.addPotentialBinding(*binding);
break;
+ }
case ConstraintKind::BridgingConversion:
case ConstraintKind::CheckedCast:
@@ -249,7 +388,7 @@
case ConstraintKind::KeyPath:
case ConstraintKind::KeyPathApplication:
// Constraints from which we can't do anything.
- continue;
+ break;
case ConstraintKind::DynamicTypeOf: {
// Direct binding of the left-hand side could result
@@ -264,7 +403,7 @@
}
// This is right-hand side, let's continue.
- continue;
+ break;
}
case ConstraintKind::Defaultable:
@@ -274,13 +413,13 @@
defaultableConstraints.push_back(constraint);
hasNonDependentMemberRelationalConstraints = true;
}
- continue;
+ break;
case ConstraintKind::Disjunction:
// FIXME: Recurse into these constraints to see whether this
// type variable is fully bound by any of them.
result.InvolvesTypeVariables = true;
- continue;
+ break;
case ConstraintKind::ConformsTo:
case ConstraintKind::SelfObjectOfProtocol:
@@ -350,7 +489,7 @@
constraint->getProtocol()});
}
- continue;
+ break;
}
case ConstraintKind::ApplicableFunction:
@@ -373,7 +512,8 @@
typeVars);
if (typeVars.size() > 1 && typeVars.count(typeVar))
result.InvolvesTypeVariables = true;
- continue;
+
+ break;
}
case ConstraintKind::ValueMember:
@@ -395,130 +535,8 @@
&result.InvolvesTypeVariables)) {
result.FullyBound = true;
}
- continue;
+ break;
}
-
- // Handle relational constraints.
- assert(constraint->getClassification() ==
- ConstraintClassification::Relational &&
- "only relational constraints handled here");
-
- // Record constraint which contributes to the
- // finding of pontential bindings.
- result.Sources.insert(constraint);
-
- auto first = simplifyType(constraint->getFirstType());
- auto second = simplifyType(constraint->getSecondType());
-
- if (first->is<TypeVariableType>() && first->isEqual(second))
- continue;
-
- Type type;
- AllowedBindingKind kind;
- if (first->getAs<TypeVariableType>() == typeVar) {
- // Upper bound for this type variable.
- type = second;
- kind = AllowedBindingKind::Subtypes;
- } else if (second->getAs<TypeVariableType>() == typeVar) {
- // Lower bound for this type variable.
- type = first;
- kind = AllowedBindingKind::Supertypes;
- } else {
- // Can't infer anything.
- if (result.InvolvesTypeVariables)
- continue;
-
- // Check whether both this type and another type variable are
- // inferable.
- SmallPtrSet<TypeVariableType *, 4> typeVars;
- findInferableTypeVars(first, typeVars);
- findInferableTypeVars(second, typeVars);
- if (typeVars.size() > 1 && typeVars.count(typeVar))
- result.InvolvesTypeVariables = true;
- continue;
- }
-
- // Do not attempt to bind to ErrorType.
- if (type->hasError())
- continue;
-
- // If the source of the binding is 'OptionalObject' constraint
- // and type variable is on the left-hand side, that means
- // that it _has_ to be of optional type, since the right-hand
- // side of the constraint is object type of the optional.
- if (constraint->getKind() == ConstraintKind::OptionalObject &&
- kind == AllowedBindingKind::Subtypes) {
- type = OptionalType::get(type);
- }
-
- // If the type we'd be binding to is a dependent member, don't try to
- // resolve this type variable yet.
- if (type->is<DependentMemberType>()) {
- if (!ConstraintSystem::typeVarOccursInType(
- typeVar, type, &result.InvolvesTypeVariables)) {
- hasDependentMemberRelationalConstraints = true;
- }
- continue;
- }
- hasNonDependentMemberRelationalConstraints = true;
-
- // Check whether we can perform this binding.
- // FIXME: this has a super-inefficient extraneous simplifyType() in it.
- bool isNilLiteral = false;
- bool *isNilLiteralPtr = nullptr;
- if (!addOptionalSupertypeBindings && kind == AllowedBindingKind::Supertypes)
- isNilLiteralPtr = &isNilLiteral;
- if (auto boundType = checkTypeOfBinding(typeVar, type, isNilLiteralPtr)) {
- type = *boundType;
- if (type->hasTypeVariable())
- result.InvolvesTypeVariables = true;
- } else {
- // If the bound is a 'nil' literal type, add optional supertype bindings.
- if (isNilLiteral) {
- addOptionalSupertypeBindings = true;
- continue;
- }
-
- result.InvolvesTypeVariables = true;
- continue;
- }
-
- // Don't deduce autoclosure types or single-element, non-variadic
- // tuples.
- if (shouldBindToValueType(constraint)) {
- if (auto funcTy = type->getAs<FunctionType>()) {
- if (funcTy->isAutoClosure())
- type = funcTy->getResult();
- }
-
- type = type->getWithoutImmediateLabel();
- }
-
- // Make sure we aren't trying to equate type variables with different
- // lvalue-binding rules.
- if (auto otherTypeVar =
- type->lookThroughAllOptionalTypes()->getAs<TypeVariableType>()) {
- if (typeVar->getImpl().canBindToLValue() !=
- otherTypeVar->getImpl().canBindToLValue())
- continue;
- }
-
- // BindParam constraints are not reflexive and must be treated specially.
- if (constraint->getKind() == ConstraintKind::BindParam) {
- if (kind == AllowedBindingKind::Subtypes) {
- if (auto *lvt = type->getAs<LValueType>()) {
- type = InOutType::get(lvt->getObjectType());
- }
- } else if (kind == AllowedBindingKind::Supertypes) {
- if (auto *iot = type->getAs<InOutType>()) {
- type = LValueType::get(iot->getObjectType());
- }
- }
- kind = AllowedBindingKind::Exact;
- }
-
- if (exactTypes.insert(type->getCanonicalType()).second)
- result.addPotentialBinding({type, kind, constraint->getKind()});
}
// If we have any literal constraints, check whether there is already a
diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h
index f757103..6a3ee66 100644
--- a/lib/Sema/ConstraintSystem.h
+++ b/lib/Sema/ConstraintSystem.h
@@ -2866,6 +2866,16 @@
Optional<Type> checkTypeOfBinding(TypeVariableType *typeVar, Type type,
bool *isNilLiteral = nullptr);
Optional<PotentialBindings> determineBestBindings();
+ Optional<ConstraintSystem::PotentialBinding>
+ getPotentialBindingForRelationalConstraint(
+ PotentialBindings &result, Constraint *constraint,
+ bool &hasDependentMemberRelationalConstraints,
+ bool &hasNonDependentMemberRelationalConstraints,
+ bool &addOptionalSupertypeBindings);
+
+ Optional<PotentialBinding>
+ getPotentialBindingForRelationalConstraint(PotentialBindings &result,
+ Constraint *constraint);
PotentialBindings getPotentialBindings(TypeVariableType *typeVar);
bool