Skip to content

Commit e5b63fa

Browse files
committed
[ConstraintSystem] NFC: Unify type variable and disjunction choice representation
Introduce `TypeBinding` interface with a single `attempt` method which is useful to encapsulate specific binding logic used for attempting disjunction choices and type variable bindings under a single interface. This makes it easier to unify top-level logic responsible for binding enumeration. It should also make it possible to introduce unified binding producer interface in the future.
1 parent 7ad7e1d commit e5b63fa

File tree

3 files changed

+104
-63
lines changed

3 files changed

+104
-63
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ static SmallVector<Type, 4> enumerateDirectSupertypes(Type type) {
776776
return result;
777777
}
778778

779-
bool TypeVarBindingGenerator::computeNext() {
779+
bool TypeVarBindingProducer::computeNext() {
780780
SmallVector<Binding, 4> newBindings;
781781
auto addNewBinding = [&](Binding binding) {
782782
auto type = binding.BindingType;
@@ -848,3 +848,34 @@ bool TypeVarBindingGenerator::computeNext() {
848848
Bindings = std::move(newBindings);
849849
return true;
850850
}
851+
852+
void TypeVariableBinding::attempt(ConstraintSystem &cs) const {
853+
auto type = Binding.BindingType;
854+
auto *locator = TypeVar->getImpl().getLocator();
855+
856+
if (Binding.DefaultedProtocol) {
857+
type = cs.openUnboundGenericType(type, locator);
858+
type = type->reconstituteSugar(/*recursive=*/false);
859+
} else if (Binding.BindingSource == ConstraintKind::ArgumentConversion &&
860+
!type->hasTypeVariable() && cs.isCollectionType(type)) {
861+
// If the type binding comes from the argument conversion, let's
862+
// instead of binding collection types directly, try to bind
863+
// using temporary type variables substituted for element
864+
// types, that's going to ensure that subtype relationship is
865+
// always preserved.
866+
auto *BGT = type->castTo<BoundGenericType>();
867+
auto UGT = UnboundGenericType::get(BGT->getDecl(), BGT->getParent(),
868+
BGT->getASTContext());
869+
870+
type = cs.openUnboundGenericType(UGT, locator);
871+
type = type->reconstituteSugar(/*recursive=*/false);
872+
}
873+
874+
// FIXME: We want the locator that indicates where the binding came
875+
// from.
876+
cs.addConstraint(ConstraintKind::Bind, TypeVar, type, locator);
877+
878+
// If this was from a defaultable binding note that.
879+
if (Binding.isDefaultableBinding())
880+
cs.DefaultedConstraints.push_back(Binding.DefaultableBinding);
881+
}

lib/Sema/CSSolver.cpp

Lines changed: 20 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -527,38 +527,10 @@ bool ConstraintSystem::tryTypeVariableBindings(
527527
bool anySolved = false;
528528
bool sawFirstLiteralConstraint = false;
529529

530-
auto attemptTypeVarBinding = [&](PotentialBinding &binding) -> bool {
531-
auto type = binding.BindingType;
532-
530+
auto attemptTypeVarBinding = [&](TypeVariableBinding &binding) -> bool {
533531
// Try to solve the system with typeVar := type
534532
ConstraintSystem::SolverScope scope(*this);
535-
if (binding.DefaultedProtocol) {
536-
type = openUnboundGenericType(type, typeVar->getImpl().getLocator());
537-
type = type->reconstituteSugar(/*recursive=*/false);
538-
} else if (binding.BindingSource == ConstraintKind::ArgumentConversion &&
539-
!type->hasTypeVariable() && isCollectionType(type)) {
540-
// If the type binding comes from the argument conversion, let's
541-
// instead of binding collection types directly, try to bind
542-
// using temporary type variables substituted for element
543-
// types, that's going to ensure that subtype relationship is
544-
// always preserved.
545-
auto *BGT = type->castTo<BoundGenericType>();
546-
auto UGT = UnboundGenericType::get(BGT->getDecl(), BGT->getParent(),
547-
BGT->getASTContext());
548-
549-
type = openUnboundGenericType(UGT, typeVar->getImpl().getLocator());
550-
type = type->reconstituteSugar(/*recursive=*/false);
551-
}
552-
553-
// FIXME: We want the locator that indicates where the binding came
554-
// from.
555-
addConstraint(ConstraintKind::Bind, typeVar, type,
556-
typeVar->getImpl().getLocator());
557-
558-
// If this was from a defaultable binding note that.
559-
if (binding.isDefaultableBinding())
560-
DefaultedConstraints.push_back(binding.DefaultableBinding);
561-
533+
binding.attempt(*this);
562534
return !solveRec(solutions);
563535
};
564536

@@ -576,7 +548,7 @@ bool ConstraintSystem::tryTypeVariableBindings(
576548
}
577549

578550
++solverState->NumTypeVariablesBound;
579-
TypeVarBindingGenerator bindings(*this, typeVar, initialBindings);
551+
TypeVarBindingProducer bindings(*this, typeVar, initialBindings);
580552
while (auto binding = bindings()) {
581553
// Try each of the bindings in turn.
582554
++solverState->NumTypeVariableBindings;
@@ -589,18 +561,18 @@ bool ConstraintSystem::tryTypeVariableBindings(
589561

590562
// If we were able to solve this without considering
591563
// default literals, don't bother looking at default literals.
592-
if (binding->DefaultedProtocol && !sawFirstLiteralConstraint)
564+
if (binding->hasDefaultedProtocol() && !sawFirstLiteralConstraint)
593565
break;
594566
}
595567

596568
if (TC.getLangOpts().DebugConstraintSolver) {
597569
auto &log = getASTContext().TypeCheckerDebug->getStream();
598570
log.indent(solverState->depth * 2)
599571
<< "(trying " << typeVar->getString()
600-
<< " := " << binding->BindingType->getString() << '\n';
572+
<< " := " << binding->getType()->getString() << '\n';
601573
}
602574

603-
if (binding->DefaultedProtocol)
575+
if (binding->hasDefaultedProtocol())
604576
sawFirstLiteralConstraint = true;
605577

606578
if (attemptTypeVarBinding(*binding))
@@ -1775,12 +1747,14 @@ Constraint *ConstraintSystem::selectDisjunction() {
17751747
}
17761748

17771749
bool ConstraintSystem::solveForDisjunctionChoices(
1778-
Disjunction &disjunction, SmallVectorImpl<Solution> &solutions) {
1750+
DisjunctionChoiceProducer &disjunction,
1751+
SmallVectorImpl<Solution> &solutions) {
17791752
Optional<Score> bestNonGenericScore;
17801753
Optional<std::pair<DisjunctionChoice, Score>> lastSolvedChoice;
17811754

17821755
// Try each of the constraints within the disjunction.
1783-
for (auto currentChoice : disjunction) {
1756+
while (auto binding = disjunction()) {
1757+
auto &currentChoice = *binding;
17841758
if (shouldSkipDisjunctionChoice(currentChoice, bestNonGenericScore))
17851759
continue;
17861760

@@ -1832,7 +1806,7 @@ bool ConstraintSystem::solveForDisjunctionChoices(
18321806
}
18331807
}
18341808

1835-
if (auto score = currentChoice.solve(solutions)) {
1809+
if (auto score = binding->attempt(solutions)) {
18361810
if (!currentChoice.isGenericOperator() &&
18371811
currentChoice.isSymmetricOperator()) {
18381812
if (!bestNonGenericScore || score < bestNonGenericScore)
@@ -1908,8 +1882,9 @@ bool ConstraintSystem::solveForDisjunction(
19081882
disjunction->shouldRememberChoice() ? disjunction->getLocator() : nullptr;
19091883
assert(!disjunction->shouldRememberChoice() || disjunction->getLocator());
19101884

1911-
auto choices = Disjunction(*this, disjunction->getNestedConstraints(),
1912-
locator, disjunction->isExplicitConversion());
1885+
auto choices =
1886+
DisjunctionChoiceProducer(*this, disjunction->getNestedConstraints(),
1887+
locator, disjunction->isExplicitConversion());
19131888

19141889
auto noSolutions = solveForDisjunctionChoices(choices, solutions);
19151890

@@ -1980,11 +1955,16 @@ bool ConstraintSystem::solveSimplified(SmallVectorImpl<Solution> &solutions) {
19801955
return false;
19811956
}
19821957

1983-
Optional<Score> DisjunctionChoice::solve(SmallVectorImpl<Solution> &solutions) {
1958+
void DisjunctionChoice::attempt(ConstraintSystem &cs) const {
19841959
CS->simplifyDisjunctionChoice(Choice);
19851960

19861961
if (ExplicitConversion)
19871962
propagateConversionInfo();
1963+
}
1964+
1965+
Optional<Score>
1966+
DisjunctionChoice::attempt(SmallVectorImpl<Solution> &solutions) {
1967+
attempt(*CS);
19881968

19891969
if (CS->solveRec(solutions))
19901970
return None;

lib/Sema/ConstraintSystem.h

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,9 @@ namespace constraints {
5252
class ConstraintGraph;
5353
class ConstraintGraphNode;
5454
class ConstraintSystem;
55-
class Disjunction;
56-
class TypeVarBindingGenerator;
55+
class DisjunctionChoiceProducer;
56+
class TypeVarBindingProducer;
57+
class TypeVariableBinding;
5758

5859
} // end namespace constraints
5960

@@ -925,7 +926,8 @@ class ConstraintSystem {
925926
friend class DisjunctionChoice;
926927
friend class Component;
927928
friend class FailureDiagnostic;
928-
friend class TypeVarBindingGenerator;
929+
friend class TypeVarBindingProducer;
930+
friend class TypeVariableBinding;
929931

930932
class SolverScope;
931933

@@ -2983,7 +2985,7 @@ class ConstraintSystem {
29832985
/// the best solution to the constraint system.
29842986
///
29852987
/// \returns true if we failed to find any solutions, false otherwise.
2986-
bool solveForDisjunctionChoices(Disjunction &disjunction,
2988+
bool solveForDisjunctionChoices(DisjunctionChoiceProducer &disjunction,
29872989
SmallVectorImpl<Solution> &solutions);
29882990

29892991
/// \brief Solve the system of constraints after it has already been
@@ -3366,7 +3368,15 @@ void simplifyLocator(Expr *&anchor,
33663368
/// null otherwise.
33673369
Expr *simplifyLocatorToAnchor(ConstraintSystem &cs, ConstraintLocator *locator);
33683370

3369-
class DisjunctionChoice {
3371+
/// Common interface to encapsulate attempting choices of
3372+
/// different entities, such as type variables (types)
3373+
/// or disjunctions (their choices).
3374+
struct TypeBinding {
3375+
virtual ~TypeBinding() {}
3376+
virtual void attempt(ConstraintSystem &cs) const = 0;
3377+
};
3378+
3379+
class DisjunctionChoice : public TypeBinding {
33703380
ConstraintSystem *CS;
33713381
unsigned Index;
33723382
Constraint *Choice;
@@ -3398,8 +3408,10 @@ class DisjunctionChoice {
33983408
bool isGenericOperator() const;
33993409
bool isSymmetricOperator() const;
34003410

3411+
void attempt(ConstraintSystem &cs) const override;
3412+
34013413
/// \brief Apply given choice to the system and try to solve it.
3402-
Optional<Score> solve(SmallVectorImpl<Solution> &solutions);
3414+
Optional<Score> attempt(SmallVectorImpl<Solution> &solutions);
34033415

34043416
operator Constraint *() { return Choice; }
34053417

@@ -3428,7 +3440,25 @@ class DisjunctionChoice {
34283440
}
34293441
};
34303442

3431-
class TypeVarBindingGenerator {
3443+
class TypeVariableBinding : public TypeBinding {
3444+
TypeVariableType *TypeVar;
3445+
ConstraintSystem::PotentialBinding Binding;
3446+
3447+
public:
3448+
TypeVariableBinding(TypeVariableType *typeVar,
3449+
ConstraintSystem::PotentialBinding &binding)
3450+
: TypeVar(typeVar), Binding(binding) {}
3451+
3452+
Type getType() const { return Binding.BindingType; }
3453+
3454+
void attempt(ConstraintSystem &cs) const override;
3455+
3456+
bool isDefaultableBinding() const { return Binding.isDefaultableBinding(); }
3457+
3458+
bool hasDefaultedProtocol() const { return Binding.DefaultedProtocol; }
3459+
};
3460+
3461+
class TypeVarBindingProducer {
34323462
using BindingKind = ConstraintSystem::AllowedBindingKind;
34333463
using Binding = ConstraintSystem::PotentialBinding;
34343464

@@ -3446,19 +3476,19 @@ class TypeVarBindingGenerator {
34463476
llvm::SmallPtrSet<TypeBase *, 4> BoundTypes;
34473477

34483478
public:
3449-
TypeVarBindingGenerator(ConstraintSystem &cs, TypeVariableType *typeVar,
3450-
ArrayRef<Binding> initialBindings)
3479+
TypeVarBindingProducer(ConstraintSystem &cs, TypeVariableType *typeVar,
3480+
ArrayRef<Binding> initialBindings)
34513481
: CS(cs), TypeVar(typeVar),
34523482
Bindings(initialBindings.begin(), initialBindings.end()) {}
34533483

3454-
Optional<Binding> operator()() {
3484+
Optional<TypeVariableBinding> operator()() {
34553485
// Once we reach the end of the current bindings
34563486
// let's try to compute new ones, e.g. supertypes,
34573487
// literal defaults, if that fails, we are done.
34583488
if (needsToComputeNext() && !computeNext())
34593489
return None;
34603490

3461-
return Bindings[Index++];
3491+
return TypeVariableBinding(TypeVar, Bindings[Index++]);
34623492
}
34633493

34643494
/// Check whether generator would have to compute next
@@ -3481,7 +3511,7 @@ class TypeVarBindingGenerator {
34813511
/// Iterator over disjunction choices, makes it
34823512
/// easy to work with disjunction and encapsulates
34833513
/// some other important information such as locator.
3484-
class Disjunction {
3514+
class DisjunctionChoiceProducer {
34853515
ConstraintSystem &CS;
34863516
ArrayRef<Constraint *> Choices;
34873517
ConstraintLocator *Locator;
@@ -3490,20 +3520,20 @@ class Disjunction {
34903520
unsigned Index = 0;
34913521

34923522
public:
3493-
Disjunction(ConstraintSystem &cs, ArrayRef<Constraint *> choices,
3494-
ConstraintLocator *locator, bool explicitConversion)
3523+
DisjunctionChoiceProducer(ConstraintSystem &cs,
3524+
ArrayRef<Constraint *> choices,
3525+
ConstraintLocator *locator, bool explicitConversion)
34953526
: CS(cs), Choices(choices), Locator(locator),
34963527
IsExplicitConversion(explicitConversion) {}
34973528

3498-
const Disjunction &begin() const { return *this; }
3499-
const Disjunction &end() const { return *this; }
3500-
3501-
bool operator!=(const Disjunction &) const { return Index < Choices.size(); }
3502-
3503-
void operator++() { ++Index; }
3529+
Optional<DisjunctionChoice> operator()() {
3530+
unsigned currIndex = Index;
3531+
if (currIndex >= Choices.size())
3532+
return None;
35043533

3505-
DisjunctionChoice operator*() const {
3506-
return {&CS, Index, Choices[Index], IsExplicitConversion};
3534+
++Index;
3535+
return DisjunctionChoice(&CS, currIndex, Choices[currIndex],
3536+
IsExplicitConversion);
35073537
}
35083538

35093539
ConstraintLocator *getLocator() const { return Locator; }

0 commit comments

Comments
 (0)