Skip to content

Commit df7af00

Browse files
committed
[CSBindings] Separate inference storage from final product usable by the solver
`PotentialBindings` lost most of its responsibilities, and are no longer comparable. Their main purpose now is binding and metadata tracking (introduction/retraction). New `BindingSet` type is something that represents a set of bindings at the current step of the solver.
1 parent 9372215 commit df7af00

File tree

8 files changed

+431
-355
lines changed

8 files changed

+431
-355
lines changed

include/swift/Sema/CSBindings.h

Lines changed: 177 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -220,34 +220,27 @@ struct LiteralRequirement {
220220
};
221221

222222
struct PotentialBindings {
223-
using BindingScore =
224-
std::tuple<bool, bool, bool, bool, bool, unsigned char, int>;
225-
226223
/// The constraint system this type variable and its bindings belong to.
227224
ConstraintSystem &CS;
228225

229226
TypeVariableType *TypeVar;
230227

231228
/// The set of potential bindings.
232-
llvm::SmallSetVector<PotentialBinding, 4> Bindings;
229+
llvm::SmallVector<PotentialBinding, 4> Bindings;
233230

234231
/// The set of protocol requirements placed on this type variable.
235232
llvm::SmallVector<Constraint *, 4> Protocols;
236233

237-
/// The set of transitive protocol requirements inferred through
238-
/// subtype/conversion/equivalence relations with other type variables.
239-
llvm::Optional<llvm::SmallPtrSet<Constraint *, 4>> TransitiveProtocols;
240-
241234
/// The set of unique literal protocol requirements placed on this
242235
/// type variable or inferred transitively through subtype chains.
243236
///
244237
/// Note that ordering is important when it comes to bindings, we'd
245238
/// like to add any "direct" default types first to attempt them
246239
/// before transitive ones.
247-
llvm::SmallMapVector<ProtocolDecl *, LiteralRequirement, 2> Literals;
240+
llvm::SmallPtrSet<Constraint *, 2> Literals;
248241

249242
/// The set of constraints which would be used to infer default types.
250-
llvm::SmallDenseMap<CanType, Constraint *, 2> Defaults;
243+
llvm::SmallPtrSet<Constraint *, 2> Defaults;
251244

252245
/// The set of constraints which delay attempting this type variable.
253246
llvm::TinyPtrVector<Constraint *> DelayedBy;
@@ -274,49 +267,81 @@ struct PotentialBindings {
274267
PotentialBindings(ConstraintSystem &cs, TypeVariableType *typeVar)
275268
: CS(cs), TypeVar(typeVar) {}
276269

277-
/// Determine whether the set of bindings is non-empty.
278-
explicit operator bool() const {
279-
return hasViableBindings()|| isDirectHole();
280-
}
270+
void addDefault(Constraint *constraint);
281271

282-
/// Determine whether this set has any "viable" (or non-hole) bindings.
283-
///
284-
/// A viable binding could be - a direct or transitive binding
285-
/// inferred from a constraint, literal binding, or defaltable
286-
/// binding.
287-
///
288-
/// A hole is not considered a viable binding since it doesn't
289-
/// add any new type information to constraint system.
290-
bool hasViableBindings() const {
291-
return !Bindings.empty() || getNumViableLiteralBindings() > 0 ||
292-
!Defaults.empty();
272+
void addLiteral(Constraint *constraint);
273+
274+
/// Add a potential binding to the list of bindings,
275+
/// coalescing supertype bounds when we are able to compute the meet.
276+
void addPotentialBinding(PotentialBinding binding);
277+
278+
/// Check if this binding is viable for inclusion in the set.
279+
bool isViable(PotentialBinding &binding) const;
280+
281+
bool isGenericParameter() const;
282+
283+
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;
293290
}
294291

295-
/// Determines whether this type variable could be `nil`,
296-
/// which means that all of its bindings should be optional.
297-
bool canBeNil() const;
292+
private:
293+
/// Attempt to infer a new binding and other useful information
294+
/// (i.e. whether bindings should be delayed) from the given
295+
/// relational constraint.
296+
Optional<PotentialBinding> inferFromRelational(Constraint *constraint);
298297

299-
/// Determine whether attempting this type variable should be
300-
/// delayed until the rest of the constraint system is considered
301-
/// "fully bound" meaning constraints, which affect completeness
302-
/// of the binding set, for this type variable such as - member
303-
/// constraint, disjunction, function application etc. - are simplified.
298+
public:
299+
void infer(Constraint *constraint);
300+
301+
/// Retract all bindings and other information related to a given
302+
/// constraint from this binding set.
304303
///
305-
/// Note that in some situations i.e. when there are no more
306-
/// disjunctions or type variables left to attempt, it's still
307-
/// okay to attempt "delayed" type variable to make forward progress.
308-
bool isDelayed() const;
304+
/// This would happen when constraint is simplified or solver backtracks
305+
/// (either from overload choice or (some) type variable binding).
306+
void retract(Constraint *constraint);
307+
};
309308

310-
/// Whether the bindings of this type involve other type variables,
311-
/// or the type variable itself is adjacent to other type variables
312-
/// that could become valid bindings in the future.
313-
bool involvesTypeVariables() const;
309+
class BindingSet {
310+
using BindingScore =
311+
std::tuple<bool, bool, bool, bool, bool, unsigned char, int>;
314312

315-
/// Whether the bindings represent (potentially) incomplete set,
316-
/// there is no way to say with absolute certainty if that's the
317-
/// case, but that could happen when certain constraints like
318-
/// `bind param` are present in the system.
319-
bool isPotentiallyIncomplete() const;
313+
ConstraintSystem &CS;
314+
315+
TypeVariableType *TypeVar;
316+
317+
PotentialBindings Info;
318+
319+
public:
320+
llvm::SmallSetVector<PotentialBinding, 4> Bindings;
321+
llvm::SmallMapVector<ProtocolDecl *, LiteralRequirement, 2> Literals;
322+
llvm::SmallDenseMap<CanType, Constraint *, 2> Defaults;
323+
324+
/// The set of transitive protocol requirements inferred through
325+
/// subtype/conversion/equivalence relations with other type variables.
326+
llvm::Optional<llvm::SmallPtrSet<Constraint *, 4>> TransitiveProtocols;
327+
328+
BindingSet(const PotentialBindings info)
329+
: CS(info.CS), TypeVar(info.TypeVar), Info(info) {
330+
for (auto *literal : info.Literals)
331+
addLiteralRequirement(literal);
332+
333+
for (const auto &binding : info.Bindings)
334+
addBinding(binding);
335+
336+
for (auto *constraint : info.Defaults)
337+
addDefault(constraint);
338+
}
339+
340+
ConstraintSystem &getConstraintSystem() const { return CS; }
341+
342+
TypeVariableType *getTypeVariable() const { return Info.TypeVar; }
343+
344+
bool canBeNil() const;
320345

321346
/// If this type variable doesn't have any viable bindings, or
322347
/// if there is only one binding and it's a placeholder type, consider
@@ -340,6 +365,28 @@ struct PotentialBindings {
340365
/// bound to a placeholder type.
341366
bool isDirectHole() const;
342367

368+
/// Determine whether attempting this type variable should be
369+
/// delayed until the rest of the constraint system is considered
370+
/// "fully bound" meaning constraints, which affect completeness
371+
/// of the binding set, for this type variable such as - member
372+
/// constraint, disjunction, function application etc. - are simplified.
373+
///
374+
/// Note that in some situations i.e. when there are no more
375+
/// disjunctions or type variables left to attempt, it's still
376+
/// okay to attempt "delayed" type variable to make forward progress.
377+
bool isDelayed() const;
378+
379+
/// Whether the bindings of this type involve other type variables,
380+
/// or the type variable itself is adjacent to other type variables
381+
/// that could become valid bindings in the future.
382+
bool involvesTypeVariables() const;
383+
384+
/// Whether the bindings represent (potentially) incomplete set,
385+
/// there is no way to say with absolute certainty if that's the
386+
/// case, but that could happen when certain constraints like
387+
/// `bind param` are present in the system.
388+
bool isPotentiallyIncomplete() const;
389+
343390
/// Determine if the bindings only constrain the type variable from above
344391
/// with an existential type; such a binding is not very helpful because
345392
/// it's impossible to enumerate the existential type's subtypes.
@@ -353,6 +400,29 @@ struct PotentialBindings {
353400
});
354401
}
355402

403+
explicit operator bool() const {
404+
return hasViableBindings() || isDirectHole();
405+
}
406+
407+
/// Determine whether this set has any "viable" (or non-hole) bindings.
408+
///
409+
/// A viable binding could be - a direct or transitive binding
410+
/// inferred from a constraint, literal binding, or defaltable
411+
/// binding.
412+
///
413+
/// A hole is not considered a viable binding since it doesn't
414+
/// add any new type information to constraint system.
415+
bool hasViableBindings() const {
416+
return !Bindings.empty() || getNumViableLiteralBindings() > 0 ||
417+
!Defaults.empty();
418+
}
419+
420+
LiteralBindingKind getLiteralKind() const;
421+
422+
ArrayRef<Constraint *> getConformanceRequirements() const {
423+
return Info.Protocols;
424+
}
425+
356426
unsigned getNumViableLiteralBindings() const;
357427

358428
unsigned getNumViableDefaultableBindings() const {
@@ -383,46 +453,8 @@ struct PotentialBindings {
383453
return numDefaultable - unviable;
384454
}
385455

386-
static BindingScore formBindingScore(const PotentialBindings &b);
387-
388-
/// Compare two sets of bindings, where \c x < y indicates that
389-
/// \c x is a better set of bindings that \c y.
390-
friend bool operator<(const PotentialBindings &x,
391-
const PotentialBindings &y) {
392-
auto xScore = formBindingScore(x);
393-
auto yScore = formBindingScore(y);
394-
395-
if (xScore < yScore)
396-
return true;
397-
398-
if (yScore < xScore)
399-
return false;
400-
401-
auto xDefaults = x.getNumViableDefaultableBindings();
402-
auto yDefaults = y.getNumViableDefaultableBindings();
403-
404-
// If there is a difference in number of default types,
405-
// prioritize bindings with fewer of them.
406-
if (xDefaults != yDefaults)
407-
return xDefaults < yDefaults;
408-
409-
// If neither type variable is a "hole" let's check whether
410-
// there is a subtype relationship between them and prefer
411-
// type variable which represents superclass first in order
412-
// for "subtype" type variable to attempt more bindings later.
413-
// This is required because algorithm can't currently infer
414-
// bindings for subtype transitively through superclass ones.
415-
if (!(std::get<0>(xScore) && std::get<0>(yScore))) {
416-
if (x.isSubtypeOf(y.TypeVar))
417-
return false;
418-
419-
if (y.isSubtypeOf(x.TypeVar))
420-
return true;
421-
}
422-
423-
// As a last resort, let's check if the bindings are
424-
// potentially incomplete, and if so, let's de-prioritize them.
425-
return x.isPotentiallyIncomplete() < y.isPotentiallyIncomplete();
456+
ASTNode getAssociatedCodeCompletionToken() const {
457+
return Info.AssociatedCodeCompletionToken;
426458
}
427459

428460
LiteralBindingKind getLiteralKind() const;
@@ -464,41 +496,78 @@ struct PotentialBindings {
464496
/// \param inferredBindings The set of all bindings inferred for type
465497
/// variables in the workset.
466498
void inferTransitiveBindings(
467-
const llvm::SmallDenseMap<TypeVariableType *, PotentialBindings>
499+
const llvm::SmallDenseMap<TypeVariableType *, BindingSet>
468500
&inferredBindings);
469501

470502
/// Detect subtype, conversion or equivalence relationship
471503
/// between two type variables and attempt to propagate protocol
472504
/// requirements down the subtype or equivalence chain.
473505
void inferTransitiveProtocolRequirements(
474-
llvm::SmallDenseMap<TypeVariableType *, PotentialBindings>
475-
&inferredBindings);
506+
llvm::SmallDenseMap<TypeVariableType *, BindingSet> &inferredBindings);
476507

477-
/// Attempt to infer a new binding and other useful information
478-
/// (i.e. whether bindings should be delayed) from the given
479-
/// relational constraint.
480-
Optional<PotentialBinding> inferFromRelational(Constraint *constraint);
508+
/// Finalize binding computation for this type variable by
509+
/// inferring bindings from context e.g. transitive bindings.
510+
void finalize(
511+
llvm::SmallDenseMap<TypeVariableType *, BindingSet> &inferredBindings);
481512

482-
public:
483-
void infer(Constraint *constraint);
513+
/// Check if this binding is favored over a disjunction e.g.
514+
/// if it has only concrete types or would resolve a closure.
515+
bool favoredOverDisjunction(Constraint *disjunction) const;
484516

485-
/// Retract all bindings and other information related to a given
486-
/// constraint from this binding set.
487-
///
488-
/// This would happen when constraint is simplified or solver backtracks
489-
/// (either from overload choice or (some) type variable binding).
490-
void retract(Constraint *constraint);
517+
static BindingScore formBindingScore(const BindingSet &b);
491518

492-
/// Finalize binding computation for this type variable by
493-
/// inferring bindings from context e.g. transitive bindings.
494-
void finalize(llvm::SmallDenseMap<TypeVariableType *, PotentialBindings>
495-
&inferredBindings);
519+
/// Compare two sets of bindings, where \c x < y indicates that
520+
/// \c x is a better set of bindings that \c y.
521+
friend bool operator<(const BindingSet &x, const BindingSet &y) {
522+
auto xScore = formBindingScore(x);
523+
auto yScore = formBindingScore(y);
524+
525+
if (xScore < yScore)
526+
return true;
527+
528+
if (yScore < xScore)
529+
return false;
496530

497-
void dump(llvm::raw_ostream &out,
498-
unsigned indent = 0) const LLVM_ATTRIBUTE_USED;
531+
auto xDefaults = x.getNumViableDefaultableBindings();
532+
auto yDefaults = y.getNumViableDefaultableBindings();
533+
534+
// If there is a difference in number of default types,
535+
// prioritize bindings with fewer of them.
536+
if (xDefaults != yDefaults)
537+
return xDefaults < yDefaults;
499538

539+
// If neither type variable is a "hole" let's check whether
540+
// there is a subtype relationship between them and prefer
541+
// type variable which represents superclass first in order
542+
// for "subtype" type variable to attempt more bindings later.
543+
// This is required because algorithm can't currently infer
544+
// bindings for subtype transitively through superclass ones.
545+
if (!(std::get<0>(xScore) && std::get<0>(yScore))) {
546+
if (x.Info.isSubtypeOf(y.getTypeVariable()))
547+
return false;
548+
549+
if (y.Info.isSubtypeOf(x.getTypeVariable()))
550+
return true;
551+
}
552+
553+
// As a last resort, let's check if the bindings are
554+
// potentially incomplete, and if so, let's de-prioritize them.
555+
return x.isPotentiallyIncomplete() < y.isPotentiallyIncomplete();
556+
}
557+
558+
void dump(llvm::raw_ostream &out, unsigned indent) const;
500559
void dump(TypeVariableType *typeVar, llvm::raw_ostream &out,
501-
unsigned indent = 0) const LLVM_ATTRIBUTE_USED;
560+
unsigned indent) const;
561+
562+
private:
563+
void addBinding(PotentialBinding binding);
564+
565+
void addLiteralRequirement(Constraint *literal);
566+
567+
void addDefault(Constraint *constraint) {
568+
auto defaultTy = constraint->getSecondType();
569+
Defaults.insert({defaultTy->getCanonicalType(), constraint});
570+
}
502571
};
503572

504573
} // end namespace inference

include/swift/Sema/ConstraintSystem.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4633,12 +4633,11 @@ class ConstraintSystem {
46334633
ConstraintKind bodyResultConstraintKind,
46344634
ConstraintLocatorBuilder locator);
46354635

4636-
Optional<PotentialBindings> determineBestBindings();
4636+
Optional<BindingSet> determineBestBindings();
46374637

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

46434642
private:
46444643
/// Add a constraint to the constraint system.
@@ -5406,7 +5405,7 @@ class TypeVarBindingProducer : public BindingProducer<TypeVariableBinding> {
54065405
public:
54075406
using Element = TypeVariableBinding;
54085407

5409-
TypeVarBindingProducer(PotentialBindings &bindings);
5408+
TypeVarBindingProducer(BindingSet &bindings);
54105409

54115410
/// Retrieve a set of bindings available in the current state.
54125411
ArrayRef<Binding> getCurrentBindings() const { return Bindings; }

0 commit comments

Comments
 (0)