Skip to content

Commit fbc11f4

Browse files
committed
[ConstraintSystem] Implement incremental binding computation
1 parent df7af00 commit fbc11f4

File tree

9 files changed

+488
-100
lines changed

9 files changed

+488
-100
lines changed

include/swift/Sema/CSBindings.h

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -260,9 +260,9 @@ struct PotentialBindings {
260260
/// is a subtype of, supertype of or is equivalent to. This is used
261261
/// to determine ordering inside of a chain of subtypes to help infer
262262
/// transitive bindings and protocol requirements.
263-
llvm::SmallMapVector<TypeVariableType *, Constraint *, 4> SubtypeOf;
264-
llvm::SmallMapVector<TypeVariableType *, Constraint *, 4> SupertypeOf;
265-
llvm::SmallMapVector<TypeVariableType *, Constraint *, 4> EquivalentTo;
263+
llvm::SmallSetVector<std::pair<TypeVariableType *, Constraint *>, 4> SubtypeOf;
264+
llvm::SmallSetVector<std::pair<TypeVariableType *, Constraint *>, 4> SupertypeOf;
265+
llvm::SmallSetVector<std::pair<TypeVariableType *, Constraint *>, 4> EquivalentTo;
266266

267267
PotentialBindings(ConstraintSystem &cs, TypeVariableType *typeVar)
268268
: CS(cs), TypeVar(typeVar) {}
@@ -275,18 +275,15 @@ struct PotentialBindings {
275275
/// coalescing supertype bounds when we are able to compute the meet.
276276
void addPotentialBinding(PotentialBinding binding);
277277

278-
/// Check if this binding is viable for inclusion in the set.
279-
bool isViable(PotentialBinding &binding) const;
280-
281278
bool isGenericParameter() const;
282279

283280
bool isSubtypeOf(TypeVariableType *typeVar) const {
284-
auto result = SubtypeOf.find(typeVar);
285-
if (result == SubtypeOf.end())
286-
return false;
287-
288-
auto *constraint = result->second;
289-
return constraint->getKind() == ConstraintKind::Subtype;
281+
return llvm::any_of(
282+
SubtypeOf,
283+
[&typeVar](const std::pair<TypeVariableType *, Constraint *> &subtype) {
284+
return subtype.first == typeVar &&
285+
subtype.second->getKind() == ConstraintKind::Subtype;
286+
});
290287
}
291288

292289
private:
@@ -314,7 +311,9 @@ class BindingSet {
314311

315312
TypeVariableType *TypeVar;
316313

317-
PotentialBindings Info;
314+
const PotentialBindings &Info;
315+
316+
llvm::SmallPtrSet<TypeVariableType *, 4> AdjacentVars;
318317

319318
public:
320319
llvm::SmallSetVector<PotentialBinding, 4> Bindings;
@@ -325,7 +324,7 @@ class BindingSet {
325324
/// subtype/conversion/equivalence relations with other type variables.
326325
llvm::Optional<llvm::SmallPtrSet<Constraint *, 4>> TransitiveProtocols;
327326

328-
BindingSet(const PotentialBindings info)
327+
BindingSet(const PotentialBindings &info)
329328
: CS(info.CS), TypeVar(info.TypeVar), Info(info) {
330329
for (auto *literal : info.Literals)
331330
addLiteralRequirement(literal);
@@ -335,6 +334,9 @@ class BindingSet {
335334

336335
for (auto *constraint : info.Defaults)
337336
addDefault(constraint);
337+
338+
for (auto &entry : info.AdjacentVars)
339+
AdjacentVars.insert(entry.first);
338340
}
339341

340342
ConstraintSystem &getConstraintSystem() const { return CS; }
@@ -400,6 +402,9 @@ class BindingSet {
400402
});
401403
}
402404

405+
/// Check if this binding is viable for inclusion in the set.
406+
bool isViable(PotentialBinding &binding) const;
407+
403408
explicit operator bool() const {
404409
return hasViableBindings() || isDirectHole();
405410
}
@@ -507,6 +512,7 @@ class BindingSet {
507512

508513
/// Finalize binding computation for this type variable by
509514
/// inferring bindings from context e.g. transitive bindings.
515+
510516
void finalize(
511517
llvm::SmallDenseMap<TypeVariableType *, BindingSet> &inferredBindings);
512518

@@ -557,7 +563,7 @@ class BindingSet {
557563

558564
void dump(llvm::raw_ostream &out, unsigned indent) const;
559565
void dump(TypeVariableType *typeVar, llvm::raw_ostream &out,
560-
unsigned indent) const;
566+
unsigned indent = 0) const LLVM_ATTRIBUTE_USED;
561567

562568
private:
563569
void addBinding(PotentialBinding binding);

include/swift/Sema/ConstraintGraph.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class ConstraintGraphNode {
7777
/// as this type variable.
7878
ArrayRef<TypeVariableType *> getEquivalenceClass() const;
7979

80-
inference::PotentialBindings &getBindings() { return *Bindings; }
80+
inference::PotentialBindings &getCurrentBindings();
8181

8282
private:
8383
/// Determines whether the type variable associated with this node
@@ -119,6 +119,13 @@ class ConstraintGraphNode {
119119
/// Remove a type variable which used to reference this type variable.
120120
void removeReferencedBy(TypeVariableType *typeVar);
121121

122+
/// Experimental {
123+
void introduceToInference(Constraint *constraint, bool notifyFixedBindings);
124+
void retractFromInference(Constraint *constraint, bool notifyFixedBindings);
125+
void reintroduceToInference(Constraint *constraint, bool notifyFixedBindings);
126+
void resetBindingSet();
127+
/// }
128+
122129
/// The constraint graph this node belongs to.
123130
ConstraintGraph &CG;
124131

include/swift/Sema/ConstraintSystem.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4635,9 +4635,9 @@ class ConstraintSystem {
46354635

46364636
Optional<BindingSet> determineBestBindings();
46374637

4638-
/// Infer bindings for the given type variable based on current
4638+
/// Get bindings for the given type variable based on current
46394639
/// state of the constraint system.
4640-
BindingSet inferBindingsFor(TypeVariableType *typeVar, bool finalize = true);
4640+
BindingSet getBindingsFor(TypeVariableType *typeVar);
46414641

46424642
private:
46434643
/// Add a constraint to the constraint system.

lib/Sema/CSBindings.cpp

Lines changed: 39 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ bool BindingSet::involvesTypeVariables() const {
133133
// on each step of the solver, but once bindings are computed
134134
// incrementally it becomes more important to double-check that
135135
// any adjacent type variables found previously are still unresolved.
136-
return llvm::any_of(Info.AdjacentVars, [](const auto &adjacent) {
137-
return !adjacent.first->getImpl().getFixedType(/*record=*/nullptr);
136+
return llvm::any_of(AdjacentVars, [](TypeVariableType *typeVar) {
137+
return !typeVar->getImpl().getFixedType(/*record=*/nullptr);
138138
});
139139
}
140140

@@ -485,6 +485,27 @@ void BindingSet::addBinding(PotentialBinding binding) {
485485
if (Bindings.count(binding))
486486
return;
487487

488+
if (!isViable(binding))
489+
return;
490+
491+
SmallPtrSet<TypeVariableType *, 4> referencedTypeVars;
492+
binding.BindingType->getTypeVariables(referencedTypeVars);
493+
494+
// If type variable is not allowed to bind to `lvalue`,
495+
// let's check if type of potential binding has any
496+
// type variables, which are allowed to bind to `lvalue`,
497+
// and postpone such type from consideration.
498+
//
499+
// This check is done here and not in `checkTypeOfBinding`
500+
// because the l-valueness of the variable might change during
501+
// solving and that would not be reflected in the graph.
502+
if (!TypeVar->getImpl().canBindToLValue()) {
503+
for (auto *typeVar : referencedTypeVars) {
504+
if (typeVar->getImpl().canBindToLValue())
505+
return;
506+
}
507+
}
508+
488509
// If this is a non-defaulted supertype binding,
489510
// check whether we can combine it with another
490511
// supertype binding by computing the 'join' of the types.
@@ -558,8 +579,10 @@ void BindingSet::addBinding(PotentialBinding binding) {
558579
}
559580
}
560581

561-
Bindings.insert(std::move(binding));
562-
>>>>>>> [CSBindings] Separate inference from final product
582+
for (auto *adjacentVar : referencedTypeVars)
583+
AdjacentVars.insert(adjacentVar);
584+
585+
(void)Bindings.insert(std::move(binding));
563586
}
564587

565588
void BindingSet::addLiteralRequirement(Constraint *constraint) {
@@ -674,8 +697,9 @@ Optional<BindingSet> ConstraintSystem::determineBestBindings() {
674697

675698
// First, let's collect all of the possible bindings.
676699
for (auto *typeVar : getTypeVariables()) {
677-
if (!typeVar->getImpl().hasRepresentativeOrFixed())
678-
cache.insert({typeVar, inferBindingsFor(typeVar, /*finalize=*/false)});
700+
if (!typeVar->getImpl().hasRepresentativeOrFixed()) {
701+
cache.insert({typeVar, getBindingsFor(typeVar)});
702+
}
679703
}
680704

681705
// Determine whether given type variable with its set of bindings is
@@ -711,7 +735,6 @@ Optional<BindingSet> ConstraintSystem::determineBestBindings() {
711735
continue;
712736

713737
auto &bindings = cachedBindings->getSecond();
714-
715738
// Before attempting to infer transitive bindings let's check
716739
// whether there are any viable "direct" bindings associated with
717740
// current type variable, if there are none - it means that this type
@@ -729,11 +752,9 @@ Optional<BindingSet> ConstraintSystem::determineBestBindings() {
729752
if (!bindings || !isViable)
730753
continue;
731754

732-
/*
733755
if (isDebugMode()) {
734756
bindings.dump(typeVar, llvm::errs(), solverState->depth * 2);
735757
}
736-
*/
737758

738759
// If these are the first bindings, or they are better than what
739760
// we saw before, use them instead.
@@ -867,17 +888,14 @@ void PotentialBindings::addPotentialBinding(PotentialBinding binding) {
867888
binding = binding.withType(binding.BindingType->getRValueType());
868889
}
869890

870-
if (!isViable(binding))
871-
return;
872-
873891
Bindings.push_back(std::move(binding));
874892
}
875893

876894
void PotentialBindings::addLiteral(Constraint *constraint) {
877895
Literals.insert(constraint);
878896
}
879897

880-
bool PotentialBindings::isViable(PotentialBinding &binding) const {
898+
bool BindingSet::isViable(PotentialBinding &binding) const {
881899
// Prevent against checking against the same opened nominal type
882900
// over and over again. Doing so means redundant work in the best
883901
// case. In the worst case, we'll produce lots of duplicate solutions
@@ -891,7 +909,7 @@ bool PotentialBindings::isViable(PotentialBinding &binding) const {
891909

892910
for (auto &existing : Bindings) {
893911
auto *existingNTD = existing.BindingType->getAnyNominal();
894-
if (existingNTD && NTD == existingNTD)
912+
if (existingNTD && NTD == existingNTD && existing.Kind == binding.Kind)
895913
return false;
896914
}
897915
}
@@ -929,29 +947,12 @@ bool BindingSet::favoredOverDisjunction(Constraint *disjunction) const {
929947
return !involvesTypeVariables();
930948
}
931949

932-
BindingSet ConstraintSystem::inferBindingsFor(TypeVariableType *typeVar,
933-
bool finalize) {
950+
BindingSet ConstraintSystem::getBindingsFor(TypeVariableType *typeVar) {
934951
assert(typeVar->getImpl().getRepresentative(nullptr) == typeVar &&
935952
"not a representative");
936953
assert(!typeVar->getImpl().getFixedType(nullptr) && "has a fixed type");
937954

938-
PotentialBindings bindings(*this, typeVar);
939-
940-
// Gather the constraints associated with this type variable.
941-
auto constraints = CG.gatherConstraints(
942-
typeVar, ConstraintGraph::GatheringKind::EquivalenceClass);
943-
944-
for (auto *constraint : constraints)
945-
bindings.infer(constraint);
946-
947-
BindingSet result{bindings};
948-
949-
if (finalize) {
950-
llvm::SmallDenseMap<TypeVariableType *, BindingSet> inferred;
951-
result.finalize(inferred);
952-
}
953-
954-
return result;
955+
return {CG[typeVar].getCurrentBindings()};
955956
}
956957

957958
/// Check whether the given type can be used as a binding for the given
@@ -960,20 +961,11 @@ BindingSet ConstraintSystem::inferBindingsFor(TypeVariableType *typeVar,
960961
/// \returns the type to bind to, if the binding is okay.
961962
static Optional<Type> checkTypeOfBinding(TypeVariableType *typeVar, Type type) {
962963
// If the type references the type variable, don't permit the binding.
963-
SmallPtrSet<TypeVariableType *, 4> referencedTypeVars;
964-
type->getTypeVariables(referencedTypeVars);
965-
if (referencedTypeVars.count(typeVar))
966-
return None;
967-
968-
// If type variable is not allowed to bind to `lvalue`,
969-
// let's check if type of potential binding has any
970-
// type variables, which are allowed to bind to `lvalue`,
971-
// and postpone such type from consideration.
972-
if (!typeVar->getImpl().canBindToLValue()) {
973-
for (auto *typeVar : referencedTypeVars) {
974-
if (typeVar->getImpl().canBindToLValue())
975-
return None;
976-
}
964+
if (type->hasTypeVariable()) {
965+
SmallPtrSet<TypeVariableType *, 4> referencedTypeVars;
966+
type->getTypeVariables(referencedTypeVars);
967+
if (referencedTypeVars.count(typeVar))
968+
return None;
977969
}
978970

979971
{
@@ -1117,13 +1109,6 @@ PotentialBindings::inferFromRelational(Constraint *constraint) {
11171109
// Check whether we can perform this binding.
11181110
if (auto boundType = checkTypeOfBinding(TypeVar, type)) {
11191111
type = *boundType;
1120-
if (type->hasTypeVariable()) {
1121-
llvm::SmallPtrSet<TypeVariableType *, 4> referencedVars;
1122-
type->getTypeVariables(referencedVars);
1123-
for (auto *var : referencedVars) {
1124-
AdjacentVars.insert({var, constraint});
1125-
}
1126-
}
11271112
} else {
11281113
auto *bindingTypeVar = type->getRValueType()->getAs<TypeVariableType>();
11291114

lib/Sema/CSSolver.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2159,7 +2159,7 @@ void DisjunctionChoice::propagateConversionInfo(ConstraintSystem &cs) const {
21592159
if (typeVar->getImpl().getFixedType(nullptr))
21602160
return;
21612161

2162-
auto bindings = cs.inferBindingsFor(typeVar);
2162+
auto bindings = cs.getBindingsFor(typeVar);
21632163

21642164
auto numBindings =
21652165
bindings.Bindings.size() + bindings.getNumViableLiteralBindings();

0 commit comments

Comments
 (0)