Skip to content

Commit 70233ac

Browse files
committed
RequirementMachine: Teach generating conformances to understand protocol refinement
For implementation reasons we want the requirement signature of a protocol to directly include all protocol refinement relationships, even if they can be derived via same-type requirements between Self and some nested type. Therefore, a protocol refinement rule [P].[Q] => [P] can only be replaced with a generating conformance equation that consists entirely of other conformance rules. This exactly simulates the existing behavior of the GSB's redundant requirements algorithm.
1 parent 371366e commit 70233ac

File tree

3 files changed

+45
-0
lines changed

3 files changed

+45
-0
lines changed

lib/AST/RequirementMachine/GeneratingConformances.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,23 @@ bool RewriteSystem::isValidConformancePath(
369369
return true;
370370
}
371371

372+
/// Rules of the form [P].[Q] => [P] encode protocol refinement and can only
373+
/// be redundant if they're equivalent to a sequence of other protocol
374+
/// refinements.
375+
///
376+
/// This helps ensure that the inheritance clause of a protocol is complete
377+
/// and correct, allowing name lookup to find associated types of inherited
378+
/// protocols while building the protocol requirement signature.
379+
bool RewriteSystem::isValidRefinementPath(
380+
const llvm::SmallVectorImpl<unsigned> &path) const {
381+
for (unsigned ruleID : path) {
382+
if (!getRule(ruleID).isProtocolRefinementRule())
383+
return false;
384+
}
385+
386+
return true;
387+
}
388+
372389
void RewriteSystem::dumpGeneratingConformanceEquation(
373390
llvm::raw_ostream &out,
374391
unsigned baseRuleID,
@@ -444,6 +461,8 @@ void RewriteSystem::computeGeneratingConformances(
444461
llvm::DenseSet<unsigned> &redundantConformances) {
445462
llvm::MapVector<unsigned, std::vector<SmallVector<unsigned, 2>>> conformancePaths;
446463

464+
llvm::DenseSet<unsigned> protocolRefinements;
465+
447466
// Prepare the initial set of equations: every non-redundant conformance rule
448467
// can be expressed as itself.
449468
for (unsigned ruleID : indices(Rules)) {
@@ -457,6 +476,9 @@ void RewriteSystem::computeGeneratingConformances(
457476
SmallVector<unsigned, 2> path;
458477
path.push_back(ruleID);
459478
conformancePaths[ruleID].push_back(path);
479+
480+
if (rule.isProtocolRefinementRule())
481+
protocolRefinements.insert(ruleID);
460482
}
461483

462484
computeCandidateConformancePaths(conformancePaths);
@@ -475,7 +497,14 @@ void RewriteSystem::computeGeneratingConformances(
475497

476498
// Find a minimal set of generating conformances.
477499
for (const auto &pair : conformancePaths) {
500+
bool isProtocolRefinement = protocolRefinements.count(pair.first) > 0;
501+
478502
for (const auto &path : pair.second) {
503+
// Only consider a protocol refinement rule to be redundant if it is
504+
// witnessed by a composition of other protocol refinement rules.
505+
if (isProtocolRefinement && !isValidRefinementPath(path))
506+
continue;
507+
479508
llvm::SmallDenseSet<unsigned, 4> visited;
480509
visited.insert(pair.first);
481510

lib/AST/RequirementMachine/RewriteSystem.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,17 @@ bool Rule::isProtocolConformanceRule() const {
6060
return false;
6161
}
6262

63+
/// If this is a rule of the form [P].[Q] => [P] where [P] and [Q] are
64+
/// protocol symbols, return true, otherwise return false.
65+
bool Rule::isProtocolRefinementRule() const {
66+
return (LHS.size() == 2 &&
67+
RHS.size() == 1 &&
68+
LHS[0] == RHS[0] &&
69+
LHS[0].getKind() == Symbol::Kind::Protocol &&
70+
LHS[1].getKind() == Symbol::Kind::Protocol &&
71+
LHS[0] != LHS[1]);
72+
}
73+
6374
void Rule::dump(llvm::raw_ostream &out) const {
6475
out << LHS << " => " << RHS;
6576
if (Permanent)

lib/AST/RequirementMachine/RewriteSystem.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ class Rule final {
8080

8181
bool isProtocolConformanceRule() const;
8282

83+
bool isProtocolRefinementRule() const;
84+
8385
/// See above for an explanation.
8486
bool isPermanent() const {
8587
return Permanent;
@@ -514,6 +516,9 @@ class RewriteSystem final {
514516
std::vector<SmallVector<unsigned, 2>>>
515517
&conformancePaths) const;
516518

519+
bool isValidRefinementPath(
520+
const llvm::SmallVectorImpl<unsigned> &path) const;
521+
517522
void dumpGeneratingConformanceEquation(
518523
llvm::raw_ostream &out,
519524
unsigned baseRuleID,

0 commit comments

Comments
 (0)