Skip to content

Commit 23b8dba

Browse files
authored
Merge pull request #35029 from xedin/bindings-finalize-refactoring
[ConstraintSystem] Make binding producer responsible for adjustments to the binding set
2 parents 186a311 + 50cc0f0 commit 23b8dba

File tree

5 files changed

+89
-69
lines changed

5 files changed

+89
-69
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5817,14 +5817,20 @@ class TypeVarBindingProducer : public BindingProducer<TypeVariableBinding> {
58175817
llvm::SmallPtrSet<CanType, 4> ExploredTypes;
58185818
llvm::SmallPtrSet<TypeBase *, 4> BoundTypes;
58195819

5820+
/// Determines whether this type variable has a
5821+
/// `ExpressibleByNilLiteral` requirement which
5822+
/// means that bindings have to either conform
5823+
/// to that protocol or be wrapped in an optional.
5824+
bool CanBeNil;
5825+
58205826
public:
58215827
using Element = TypeVariableBinding;
58225828

58235829
TypeVarBindingProducer(ConstraintSystem &cs,
5824-
ConstraintSystem::PotentialBindings &bindings)
5825-
: BindingProducer(cs, bindings.TypeVar->getImpl().getLocator()),
5826-
TypeVar(bindings.TypeVar),
5827-
Bindings(bindings.Bindings.begin(), bindings.Bindings.end()) {}
5830+
ConstraintSystem::PotentialBindings &bindings);
5831+
5832+
/// Retrieve a set of bindings available in the current state.
5833+
ArrayRef<Binding> getCurrentBindings() const { return Bindings; }
58285834

58295835
Optional<Element> operator()() override {
58305836
// Once we reach the end of the current bindings
@@ -5846,6 +5852,10 @@ class TypeVarBindingProducer : public BindingProducer<TypeVariableBinding> {
58465852
/// \returns true if some new bindings were sucessfully computed,
58475853
/// false otherwise.
58485854
bool computeNext();
5855+
5856+
/// Check whether binding type is required to either conform to
5857+
/// `ExpressibleByNilLiteral` protocol or be wrapped into an optional type.
5858+
bool requiresOptionalAdjustment(const Binding &binding) const;
58495859
};
58505860

58515861
/// Iterator over disjunction choices, makes it

lib/Sema/CSBindings.cpp

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -547,41 +547,6 @@ void ConstraintSystem::PotentialBindings::finalize(
547547
inferTransitiveBindings(cs, existingTypes, inferredBindings);
548548
inferDefaultTypes(cs, existingTypes);
549549

550-
// Adjust optionality of existing bindings based on presence of
551-
// `ExpressibleByNilLiteral` requirement.
552-
if (llvm::any_of(Protocols, [](Constraint *constraint) {
553-
auto *protocol = constraint->getProtocol();
554-
return protocol->isSpecificProtocol(
555-
KnownProtocolKind::ExpressibleByNilLiteral);
556-
})) {
557-
for (auto &binding : Bindings) {
558-
bool wrapInOptional = false;
559-
if (binding.Kind == AllowedBindingKind::Supertypes) {
560-
auto type = binding.BindingType->getRValueType();
561-
// If the type doesn't conform to ExpressibleByNilLiteral,
562-
// produce an optional of that type as a potential binding. We
563-
// overwrite the binding in place because the non-optional type
564-
// will fail to type-check against the nil-literal conformance.
565-
bool conformsToExprByNilLiteral = false;
566-
if (auto *nominalBindingDecl = type->getAnyNominal()) {
567-
SmallVector<ProtocolConformance *, 2> conformances;
568-
conformsToExprByNilLiteral = nominalBindingDecl->lookupConformance(
569-
cs.DC->getParentModule(),
570-
cs.getASTContext().getProtocol(
571-
KnownProtocolKind::ExpressibleByNilLiteral),
572-
conformances);
573-
}
574-
wrapInOptional = !conformsToExprByNilLiteral;
575-
} else if (binding.isDefaultableBinding() &&
576-
binding.BindingType->isAny()) {
577-
wrapInOptional = true;
578-
}
579-
580-
if (wrapInOptional)
581-
binding.BindingType = OptionalType::get(binding.BindingType);
582-
}
583-
}
584-
585550
// If there are no bindings, typeVar may be a hole.
586551
if (cs.shouldAttemptFixes() && Bindings.empty() &&
587552
TypeVar->getImpl().canBindToHole()) {
@@ -601,21 +566,6 @@ void ConstraintSystem::PotentialBindings::finalize(
601566

602567
addPotentialBinding(PotentialBinding::forHole(TypeVar, locator));
603568
}
604-
605-
// Let's always consider `Any` to be a last resort binding because
606-
// it's always better to infer concrete type and erase it if required
607-
// by the context.
608-
if (Bindings.size() > 1) {
609-
auto AnyTypePos =
610-
llvm::find_if(Bindings, [](const PotentialBinding &binding) {
611-
return binding.BindingType->isAny() &&
612-
!binding.isDefaultableBinding();
613-
});
614-
615-
if (AnyTypePos != Bindings.end()) {
616-
std::rotate(AnyTypePos, AnyTypePos + 1, Bindings.end());
617-
}
618-
}
619569
}
620570

621571
Optional<ConstraintSystem::PotentialBindings>

lib/Sema/CSStep.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -446,13 +446,15 @@ void TypeVariableStep::setup() {
446446
PO.PrintTypesForDebugging = true;
447447
auto &log = getDebugLogger();
448448

449+
auto initialBindings = Producer.getCurrentBindings();
449450
log << "Initial bindings: ";
450-
interleave(InitialBindings.begin(), InitialBindings.end(),
451-
[&](const Binding &binding) {
452-
log << TypeVar->getString(PO)
453-
<< " := " << binding.BindingType->getString(PO);
454-
},
455-
[&log] { log << ", "; });
451+
interleave(
452+
initialBindings.begin(), initialBindings.end(),
453+
[&](const Binding &binding) {
454+
log << TypeVar->getString(PO)
455+
<< " := " << binding.BindingType->getString(PO);
456+
},
457+
[&log] { log << ", "; });
456458

457459
log << '\n';
458460
}

lib/Sema/CSStep.h

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -479,9 +479,9 @@ class ComponentStep final : public SolverStep {
479479
template <typename P> class BindingStep : public SolverStep {
480480
using Scope = ConstraintSystem::SolverScope;
481481

482+
protected:
482483
P Producer;
483484

484-
protected:
485485
/// Indicates whether any of the attempted bindings
486486
/// produced a solution.
487487
bool AnySolved = false;
@@ -569,10 +569,6 @@ class TypeVariableStep final : public BindingStep<TypeVarBindingProducer> {
569569
using Binding = ConstraintSystem::PotentialBinding;
570570

571571
TypeVariableType *TypeVar;
572-
// A set of the initial bindings to consider, which is
573-
// also a source of follow-up "computed" bindings such
574-
// as supertypes, defaults etc.
575-
SmallVector<Binding, 4> InitialBindings;
576572

577573
/// Indicates whether source of one of the previously
578574
/// attempted bindings was a literal constraint. This
@@ -583,8 +579,7 @@ class TypeVariableStep final : public BindingStep<TypeVarBindingProducer> {
583579
public:
584580
TypeVariableStep(ConstraintSystem &cs, BindingContainer &bindings,
585581
SmallVectorImpl<Solution> &solutions)
586-
: BindingStep(cs, {cs, bindings}, solutions), TypeVar(bindings.TypeVar),
587-
InitialBindings(bindings.Bindings.begin(), bindings.Bindings.end()) {}
582+
: BindingStep(cs, {cs, bindings}, solutions), TypeVar(bindings.TypeVar) {}
588583

589584
void setup() override;
590585

@@ -593,8 +588,7 @@ class TypeVariableStep final : public BindingStep<TypeVarBindingProducer> {
593588
void print(llvm::raw_ostream &Out) override {
594589
PrintOptions PO;
595590
PO.PrintTypesForDebugging = true;
596-
Out << "TypeVariableStep for " << TypeVar->getString(PO) << " with #"
597-
<< InitialBindings.size() << " initial bindings\n";
591+
Out << "TypeVariableStep for " << TypeVar->getString(PO) << '\n';
598592
}
599593

600594
protected:

lib/Sema/ConstraintSystem.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5330,3 +5330,67 @@ bool ConstraintSystem::isReadOnlyKeyPathComponent(
53305330

53315331
return false;
53325332
}
5333+
5334+
TypeVarBindingProducer::TypeVarBindingProducer(
5335+
ConstraintSystem &cs, ConstraintSystem::PotentialBindings &bindings)
5336+
: BindingProducer(cs, bindings.TypeVar->getImpl().getLocator()),
5337+
TypeVar(bindings.TypeVar),
5338+
CanBeNil(llvm::any_of(bindings.Protocols, [](Constraint *constraint) {
5339+
auto *protocol = constraint->getProtocol();
5340+
return protocol->isSpecificProtocol(
5341+
KnownProtocolKind::ExpressibleByNilLiteral);
5342+
})) {
5343+
// A binding to `Any` which should always be considered as a last resort.
5344+
Optional<Binding> Any;
5345+
5346+
for (const auto &binding : bindings.Bindings) {
5347+
auto type = binding.BindingType;
5348+
5349+
// Adjust optionality of existing bindings based on presence of
5350+
// `ExpressibleByNilLiteral` requirement.
5351+
if (requiresOptionalAdjustment(binding)) {
5352+
Bindings.push_back(binding.withType(OptionalType::get(type)));
5353+
} else if (type->isAny()) {
5354+
Any.emplace(binding);
5355+
} else {
5356+
Bindings.push_back(binding);
5357+
}
5358+
}
5359+
5360+
// Let's always consider `Any` to be a last resort binding because
5361+
// it's always better to infer concrete type and erase it if required
5362+
// by the context.
5363+
if (Any) {
5364+
Bindings.push_back(*Any);
5365+
}
5366+
}
5367+
5368+
bool TypeVarBindingProducer::requiresOptionalAdjustment(
5369+
const Binding &binding) const {
5370+
// If type variable can't be `nil` then adjustment is
5371+
// not required.
5372+
if (!CanBeNil)
5373+
return false;
5374+
5375+
if (binding.Kind == BindingKind::Supertypes) {
5376+
auto type = binding.BindingType->getRValueType();
5377+
// If the type doesn't conform to ExpressibleByNilLiteral,
5378+
// produce an optional of that type as a potential binding. We
5379+
// overwrite the binding in place because the non-optional type
5380+
// will fail to type-check against the nil-literal conformance.
5381+
bool conformsToExprByNilLiteral = false;
5382+
if (auto *nominalBindingDecl = type->getAnyNominal()) {
5383+
SmallVector<ProtocolConformance *, 2> conformances;
5384+
conformsToExprByNilLiteral = nominalBindingDecl->lookupConformance(
5385+
CS.DC->getParentModule(),
5386+
CS.getASTContext().getProtocol(
5387+
KnownProtocolKind::ExpressibleByNilLiteral),
5388+
conformances);
5389+
}
5390+
return !conformsToExprByNilLiteral;
5391+
} else if (binding.isDefaultableBinding() && binding.BindingType->isAny()) {
5392+
return true;
5393+
}
5394+
5395+
return false;
5396+
}

0 commit comments

Comments
 (0)