Skip to content

Commit 3177145

Browse files
committed
[CSBindings] Determine literal coverage during binding set finalization
1 parent 5d86995 commit 3177145

File tree

2 files changed

+58
-64
lines changed

2 files changed

+58
-64
lines changed

include/swift/Sema/CSBindings.h

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -206,11 +206,6 @@ struct LiteralRequirement {
206206
bool canBeNil,
207207
DeclContext *useDC) const;
208208

209-
void resetCoverage() {
210-
assert(isCovered() && "literal requirement is uncovered");
211-
CoveredBy = nullptr;
212-
}
213-
214209
/// Determines whether literal protocol associated with this
215210
/// meta-information is viable for inclusion as a defaultable binding.
216211
bool viableAsBinding() const { return !isCovered() && hasDefaultType(); }
@@ -326,12 +321,12 @@ class BindingSet {
326321

327322
BindingSet(const PotentialBindings &info)
328323
: CS(info.CS), TypeVar(info.TypeVar), Info(info) {
329-
for (auto *literal : info.Literals)
330-
addLiteralRequirement(literal);
331-
332324
for (const auto &binding : info.Bindings)
333325
addBinding(binding);
334326

327+
for (auto *literal : info.Literals)
328+
addLiteralRequirement(literal);
329+
335330
for (auto *constraint : info.Defaults)
336331
addDefault(constraint);
337332

@@ -512,7 +507,6 @@ class BindingSet {
512507

513508
/// Finalize binding computation for this type variable by
514509
/// inferring bindings from context e.g. transitive bindings.
515-
516510
void finalize(
517511
llvm::SmallDenseMap<TypeVariableType *, BindingSet> &inferredBindings);
518512

@@ -574,6 +568,10 @@ class BindingSet {
574568
auto defaultTy = constraint->getSecondType();
575569
Defaults.insert({defaultTy->getCanonicalType(), constraint});
576570
}
571+
572+
/// Check whether the given binding set covers any of the
573+
/// literal protocols associated with this type variable.
574+
void determineLiteralCoverage();
577575
};
578576

579577
} // end namespace inference

lib/Sema/CSBindings.cpp

Lines changed: 51 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,8 @@ void BindingSet::finalize(
436436
inferTransitiveProtocolRequirements(inferredBindings);
437437
inferTransitiveBindings(inferredBindings);
438438

439+
determineLiteralCoverage();
440+
439441
if (auto *locator = TypeVar->getImpl().getLocator()) {
440442
if (locator->isLastElement<LocatorPathElt::MemberRefBase>()) {
441443
// If this is a base of an unresolved member chain, as a last
@@ -546,43 +548,67 @@ void BindingSet::addBinding(PotentialBinding binding) {
546548
return;
547549
}
548550

549-
// Check whether the given binding covers any of the literal protocols
550-
// associated with this type variable.
551-
{
552-
bool allowsNil = canBeNil();
551+
for (auto *adjacentVar : referencedTypeVars)
552+
AdjacentVars.insert(adjacentVar);
553553

554-
for (auto &literal : Literals) {
555-
auto *protocol = literal.first;
554+
(void)Bindings.insert(std::move(binding));
555+
}
556556

557-
// Skip conformance to `nil` protocol since it doesn't
558-
// have a default type and can't affect binding set.
559-
if (protocol->isSpecificProtocol(
560-
KnownProtocolKind::ExpressibleByNilLiteral))
561-
continue;
557+
void BindingSet::determineLiteralCoverage() {
558+
if (Literals.empty())
559+
return;
562560

563-
auto &info = literal.second;
561+
SmallVector<PotentialBinding, 4> adjustedBindings;
564562

565-
if (!info.viableAsBinding())
566-
continue;
563+
bool allowsNil = canBeNil();
567564

568-
bool isCovered = false;
569-
Type adjustedTy;
565+
for (auto binding = Bindings.begin(); binding != Bindings.end();) {
566+
bool isCovered = false;
567+
Type adjustedTy;
570568

571-
std::tie(isCovered, adjustedTy) =
572-
isLiteralCoveredBy(info, binding, allowsNil);
569+
// Tracks the number of covered literal requirements,
570+
// so checking could be stopped as soon as all of the
571+
// requirements are satisfied.
572+
unsigned numCoveredRequirements = 0;
573+
for (auto &literalRequirement : Literals) {
574+
auto &literalInfo = literalRequirement.second;
573575

574-
if (!isCovered)
576+
if (!literalInfo.viableAsBinding()) {
577+
++numCoveredRequirements;
575578
continue;
579+
}
580+
581+
std::tie(isCovered, adjustedTy) =
582+
literalInfo.isCoveredBy(*binding, CS.DC, allowsNil);
576583

577-
binding = binding.withType(adjustedTy);
578-
info.setCoveredBy(binding.getSource());
584+
if (isCovered) {
585+
literalInfo.setCoveredBy(binding->getSource());
586+
++numCoveredRequirements;
587+
break;
588+
}
579589
}
580-
}
581590

582-
for (auto *adjacentVar : referencedTypeVars)
583-
AdjacentVars.insert(adjacentVar);
591+
// If the type has been adjusted, we need to re-insert
592+
// the binding but skip all of the previous checks.
593+
//
594+
// It's okay to do this here since iteration stops after
595+
// first covering binding has been found.
596+
if (isCovered && adjustedTy) {
597+
binding = Bindings.erase(binding);
598+
adjustedBindings.push_back(binding->withType(adjustedTy));
599+
continue;
600+
}
584601

585-
(void)Bindings.insert(std::move(binding));
602+
// If all of the literal requirements are now covered
603+
// by existing bindings, there is nothing left to do.
604+
if (numCoveredRequirements == Literals.size())
605+
break;
606+
607+
++binding;
608+
}
609+
610+
for (auto &newBinding : adjustedBindings)
611+
(void)Bindings.insert(std::move(newBinding));
586612
}
587613

588614
void BindingSet::addLiteralRequirement(Constraint *constraint) {
@@ -637,36 +663,6 @@ void BindingSet::addLiteralRequirement(Constraint *constraint) {
637663
LiteralRequirement literal(
638664
constraint, TypeChecker::getDefaultType(protocol, CS.DC), isDirect);
639665

640-
if (literal.viableAsBinding()) {
641-
bool allowsNil = canBeNil();
642-
643-
for (auto binding = Bindings.begin(); binding != Bindings.end();
644-
++binding) {
645-
bool isCovered = false;
646-
Type adjustedTy;
647-
648-
std::tie(isCovered, adjustedTy) =
649-
isLiteralCoveredBy(literal, *binding, allowsNil);
650-
651-
// No luck here, let's try next literal requirement.
652-
if (!isCovered)
653-
continue;
654-
655-
// If the type has been adjusted, we need to re-insert
656-
// the binding but skip all of the previous checks.
657-
//
658-
// It's okay to do this here since iteration stops after
659-
// first covering binding has been found.
660-
if (adjustedTy) {
661-
Bindings.erase(binding);
662-
Bindings.insert(binding->withType(adjustedTy));
663-
}
664-
665-
literal.setCoveredBy(binding->getSource());
666-
break;
667-
}
668-
}
669-
670666
Literals.insert({protocol, std::move(literal)});
671667
}
672668

0 commit comments

Comments
 (0)