@@ -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+
404427void 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.
475498void 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 }
0 commit comments