@@ -582,13 +582,22 @@ void EquivalenceClassMap::addProperty(
582
582
void EquivalenceClassMap::concretizeNestedTypesFromConcreteParents (
583
583
SmallVectorImpl<std::pair<MutableTerm, MutableTerm>> &inducedRules) const {
584
584
for (const auto &equivClass : Map) {
585
- if (equivClass->isConcreteType () &&
586
- !equivClass->getConformsTo ().empty ()) {
587
- if (DebugConcretizeNestedTypes) {
585
+ if (equivClass->getConformsTo ().empty ())
586
+ continue ;
587
+
588
+ if (DebugConcretizeNestedTypes) {
589
+ if (equivClass->isConcreteType () ||
590
+ equivClass->hasSuperclassBound ()) {
588
591
llvm::dbgs () << " ^ Concretizing nested types of " ;
589
592
equivClass->dump (llvm::dbgs ());
590
593
llvm::dbgs () << " \n " ;
591
594
}
595
+ }
596
+
597
+ if (equivClass->isConcreteType ()) {
598
+ if (DebugConcretizeNestedTypes) {
599
+ llvm::dbgs () << " - via concrete type requirement\n " ;
600
+ }
592
601
593
602
concretizeNestedTypesFromConcreteParent (
594
603
equivClass->getKey (),
@@ -597,14 +606,53 @@ void EquivalenceClassMap::concretizeNestedTypesFromConcreteParents(
597
606
equivClass->getConformsTo (),
598
607
inducedRules);
599
608
}
609
+
610
+ if (equivClass->hasSuperclassBound ()) {
611
+ if (DebugConcretizeNestedTypes) {
612
+ llvm::dbgs () << " - via superclass requirement\n " ;
613
+ }
614
+
615
+ concretizeNestedTypesFromConcreteParent (
616
+ equivClass->getKey (),
617
+ equivClass->Superclass ->getSuperclass (),
618
+ equivClass->Superclass ->getSubstitutions (),
619
+ equivClass->getConformsTo (),
620
+ inducedRules);
621
+ }
600
622
}
601
623
}
602
624
603
- // / If we have an equivalence class T => { conforms_to: [ P ], concrete: Foo },
604
- // / then for each associated type A of P, we generate a new rule:
625
+ // / Suppose a same-type requirement merges two equivalence classes,
626
+ // / one of which has a conformance requirement to P and the other
627
+ // / one has a concrete type or superclass requirement.
628
+ // /
629
+ // / If the concrete type or superclass conforms to P and P has an
630
+ // / associated type A, then we need to infer an equivalence between
631
+ // / T.[P:A] and whatever the type witness for 'A' is in the
632
+ // / concrete conformance.
633
+ // /
634
+ // / For example, suppose we have a the following definitions,
635
+ // /
636
+ // / protocol Q { associatedtype V }
637
+ // / protocol P { associatedtype A; associatedtype C }
638
+ // / struct Foo<A, B : Q> : P {
639
+ // / typealias C = B.V
640
+ // / }
641
+ // /
642
+ // / together with the following equivalence class:
643
+ // /
644
+ // / T => { conforms_to: [ P ], concrete: Foo<Int, τ_0_0> with <U> }
645
+ // /
646
+ // / The type witness for A in the conformance Foo<Int, τ_0_0> : P is
647
+ // / the concrete type 'Int', which induces the following rule:
648
+ // /
649
+ // / T.[P:A].[concrete: Int] => T.[P:A]
650
+ // /
651
+ // / Whereas the type witness for B in the same conformance is the
652
+ // / abstract type 'τ_0_0.V', which via the substitutions <U> corresponds
653
+ // / to the term 'U.V', and therefore induces the following rule:
605
654
// /
606
- // / T.[P:A].[concrete: Foo.A] => T.[P:A] (if Foo.A is concrete)
607
- // / T.[P:A] => T.(Foo.A) (if Foo.A is abstract)
655
+ // / T.[P:B] => U.V
608
656
// /
609
657
void EquivalenceClassMap::concretizeNestedTypesFromConcreteParent (
610
658
const MutableTerm &key,
0 commit comments