Skip to content

Commit 94e9ab6

Browse files
committed
RequirementMachine: Track parent paths when computing generating conformances
1 parent b47b2d3 commit 94e9ab6

File tree

2 files changed

+120
-23
lines changed

2 files changed

+120
-23
lines changed

lib/AST/RequirementMachine/GeneratingConformances.cpp

Lines changed: 115 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -350,35 +350,51 @@ bool RewriteSystem::isValidConformancePath(
350350
llvm::SmallDenseSet<unsigned, 4> &visited,
351351
llvm::DenseSet<unsigned> &redundantConformances,
352352
const llvm::SmallVectorImpl<unsigned> &path,
353+
const llvm::MapVector<unsigned, SmallVector<unsigned, 2>> &parentPaths,
353354
const llvm::MapVector<unsigned,
354355
std::vector<SmallVector<unsigned, 2>>>
355356
&conformancePaths) const {
356357
for (unsigned ruleID : path) {
357358
if (visited.count(ruleID) > 0)
358359
return false;
359360

360-
if (!redundantConformances.count(ruleID))
361-
continue;
362-
363-
SWIFT_DEFER {
364-
visited.erase(ruleID);
365-
};
366-
visited.insert(ruleID);
361+
if (redundantConformances.count(ruleID)) {
362+
SWIFT_DEFER {
363+
visited.erase(ruleID);
364+
};
365+
visited.insert(ruleID);
366+
367+
auto found = conformancePaths.find(ruleID);
368+
assert(found != conformancePaths.end());
369+
370+
bool foundValidConformancePath = false;
371+
for (const auto &otherPath : found->second) {
372+
if (isValidConformancePath(visited, redundantConformances, otherPath,
373+
parentPaths, conformancePaths)) {
374+
foundValidConformancePath = true;
375+
break;
376+
}
377+
}
367378

368-
auto found = conformancePaths.find(ruleID);
369-
assert(found != conformancePaths.end());
379+
if (!foundValidConformancePath)
380+
return false;
381+
}
370382

371-
bool foundValidConformancePath = false;
372-
for (const auto &otherPath : found->second) {
373-
if (isValidConformancePath(visited, redundantConformances,
374-
otherPath, conformancePaths)) {
375-
foundValidConformancePath = true;
376-
break;
383+
auto found = parentPaths.find(ruleID);
384+
if (found != parentPaths.end()) {
385+
SWIFT_DEFER {
386+
visited.erase(ruleID);
387+
};
388+
visited.insert(ruleID);
389+
390+
// If 'req' is based on some other conformance requirement
391+
// `T.[P.]A : Q', we want to make sure that we have a
392+
// non-redundant derivation for 'T : P'.
393+
if (!isValidConformancePath(visited, redundantConformances, found->second,
394+
parentPaths, conformancePaths)) {
395+
return false;
377396
}
378397
}
379-
380-
if (!foundValidConformancePath)
381-
return false;
382398
}
383399

384400
return true;
@@ -401,6 +417,13 @@ bool RewriteSystem::isValidRefinementPath(
401417
return true;
402418
}
403419

420+
void RewriteSystem::dumpConformancePath(
421+
llvm::raw_ostream &out,
422+
const SmallVectorImpl<unsigned> &path) const {
423+
for (unsigned ruleID : path)
424+
out << "(" << getRule(ruleID).getLHS() << ")";
425+
}
426+
404427
void RewriteSystem::dumpGeneratingConformanceEquation(
405428
llvm::raw_ostream &out,
406429
unsigned baseRuleID,
@@ -413,8 +436,8 @@ void RewriteSystem::dumpGeneratingConformanceEquation(
413436
out << "";
414437
else
415438
first = false;
416-
for (unsigned ruleID : path)
417-
out << "(" << getRule(ruleID).getLHS() << ")";
439+
440+
dumpConformancePath(out, path);
418441
}
419442
}
420443

@@ -474,8 +497,22 @@ void RewriteSystem::verifyGeneratingConformanceEquations(
474497
/// conformance rules.
475498
void RewriteSystem::computeGeneratingConformances(
476499
llvm::DenseSet<unsigned> &redundantConformances) {
500+
// Maps a conformance rule to a conformance path deriving the subject type's
501+
// base type. For example, consider the following conformance rule:
502+
//
503+
// T.[P:A].[Q:B].[R] => T.[P:A].[Q:B]
504+
//
505+
// The subject type is T.[P:A].[Q:B]; in order to derive the metadata, we need
506+
// the witness table for T.[P:A] : [Q] first, by computing a conformance access
507+
// path for the term T.[P:A].[Q], known as the 'parent path'.
508+
llvm::MapVector<unsigned, SmallVector<unsigned, 2>> parentPaths;
509+
510+
// Maps a conformance rule to a list of paths. Each path in the list is a unique
511+
// derivation of the conformance in terms of other conformance rules.
477512
llvm::MapVector<unsigned, std::vector<SmallVector<unsigned, 2>>> conformancePaths;
478513

514+
// The set of conformance rules which are protocol refinements, that is rules of
515+
// the form [P].[Q] => [P].
479516
llvm::DenseSet<unsigned> protocolRefinements;
480517

481518
// Prepare the initial set of equations: every non-redundant conformance rule
@@ -492,8 +529,56 @@ void RewriteSystem::computeGeneratingConformances(
492529
path.push_back(ruleID);
493530
conformancePaths[ruleID].push_back(path);
494531

495-
if (rule.isProtocolRefinementRule())
532+
if (rule.isProtocolRefinementRule()) {
496533
protocolRefinements.insert(ruleID);
534+
continue;
535+
}
536+
537+
auto lhs = rule.getLHS();
538+
539+
auto parentSymbol = lhs[lhs.size() - 2];
540+
541+
// The last element is a protocol symbol, because this is a conformance rule.
542+
// The second to last symbol is either an associated type, protocol or generic
543+
// parameter symbol.
544+
switch (parentSymbol.getKind()) {
545+
case Symbol::Kind::AssociatedType: {
546+
// If we have a rule of the form X.[P:Y].[Q] => X.[P:Y] wih non-empty X,
547+
// then the parent type is X.[P].
548+
if (lhs.size() == 2)
549+
continue;
550+
551+
MutableTerm mutTerm(lhs.begin(), lhs.end() - 2);
552+
assert(!mutTerm.empty());
553+
554+
const auto protos = parentSymbol.getProtocols();
555+
assert(protos.size() == 1);
556+
557+
bool simplified = simplify(mutTerm);
558+
assert(!simplified || rule.isSimplified());
559+
(void) simplified;
560+
561+
mutTerm.add(Symbol::forProtocol(protos[0], Context));
562+
563+
// Get a conformance path for X.[P] and record it.
564+
decomposeTermIntoConformanceRuleLeftHandSides(mutTerm, parentPaths[ruleID]);
565+
continue;
566+
}
567+
568+
case Symbol::Kind::GenericParam:
569+
case Symbol::Kind::Protocol:
570+
// Don't record a parent path, since the parent type is trivial (either a
571+
// generic parameter, or the protocol 'Self' type).
572+
continue;
573+
574+
case Symbol::Kind::Name:
575+
case Symbol::Kind::Layout:
576+
case Symbol::Kind::Superclass:
577+
case Symbol::Kind::ConcreteType:
578+
break;
579+
}
580+
581+
llvm_unreachable("Bad symbol kind");
497582
}
498583

499584
computeCandidateConformancePaths(conformancePaths);
@@ -506,6 +591,13 @@ void RewriteSystem::computeGeneratingConformances(
506591
pair.first, pair.second);
507592
llvm::dbgs() << "\n";
508593
}
594+
595+
llvm::dbgs() << "Parent paths:\n";
596+
for (const auto &pair : parentPaths) {
597+
llvm::dbgs() << "- " << getRule(pair.first).getLHS() << ": ";
598+
dumpConformancePath(llvm::dbgs(), pair.second);
599+
llvm::dbgs() << "\n";
600+
}
509601
}
510602

511603
verifyGeneratingConformanceEquations(conformancePaths);
@@ -523,8 +615,8 @@ void RewriteSystem::computeGeneratingConformances(
523615
llvm::SmallDenseSet<unsigned, 4> visited;
524616
visited.insert(pair.first);
525617

526-
if (isValidConformancePath(visited, redundantConformances,
527-
path, conformancePaths)) {
618+
if (isValidConformancePath(visited, redundantConformances, path,
619+
parentPaths, conformancePaths)) {
528620
redundantConformances.insert(pair.first);
529621
break;
530622
}

lib/AST/RequirementMachine/RewriteSystem.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,13 +512,18 @@ class RewriteSystem final {
512512
llvm::SmallDenseSet<unsigned, 4> &visited,
513513
llvm::DenseSet<unsigned> &redundantConformances,
514514
const llvm::SmallVectorImpl<unsigned> &path,
515+
const llvm::MapVector<unsigned, SmallVector<unsigned, 2>> &parentPaths,
515516
const llvm::MapVector<unsigned,
516517
std::vector<SmallVector<unsigned, 2>>>
517518
&conformancePaths) const;
518519

519520
bool isValidRefinementPath(
520521
const llvm::SmallVectorImpl<unsigned> &path) const;
521522

523+
void dumpConformancePath(
524+
llvm::raw_ostream &out,
525+
const SmallVectorImpl<unsigned> &path) const;
526+
522527
void dumpGeneratingConformanceEquation(
523528
llvm::raw_ostream &out,
524529
unsigned baseRuleID,

0 commit comments

Comments
 (0)