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