Skip to content

Commit 5dca8c6

Browse files
committed
RequirementMachine: Perform nested type concretization for superclass requirements too
If an equivalence class has protocol conformance requirements together with a superclass requirement, any protocols to which the superclass conforms might have nested types that need to be concretized by introducing same-type requierments between those nested types and the type witnesses in the concrete conformances of the superclass.
1 parent ac5300c commit 5dca8c6

File tree

2 files changed

+59
-7
lines changed

2 files changed

+59
-7
lines changed

lib/AST/RequirementMachine/EquivalenceClassMap.cpp

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -582,13 +582,22 @@ void EquivalenceClassMap::addProperty(
582582
void EquivalenceClassMap::concretizeNestedTypesFromConcreteParents(
583583
SmallVectorImpl<std::pair<MutableTerm, MutableTerm>> &inducedRules) const {
584584
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()) {
588591
llvm::dbgs() << "^ Concretizing nested types of ";
589592
equivClass->dump(llvm::dbgs());
590593
llvm::dbgs() << "\n";
591594
}
595+
}
596+
597+
if (equivClass->isConcreteType()) {
598+
if (DebugConcretizeNestedTypes) {
599+
llvm::dbgs() << "- via concrete type requirement\n";
600+
}
592601

593602
concretizeNestedTypesFromConcreteParent(
594603
equivClass->getKey(),
@@ -597,14 +606,53 @@ void EquivalenceClassMap::concretizeNestedTypesFromConcreteParents(
597606
equivClass->getConformsTo(),
598607
inducedRules);
599608
}
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+
}
600622
}
601623
}
602624

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:
605654
///
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
608656
///
609657
void EquivalenceClassMap::concretizeNestedTypesFromConcreteParent(
610658
const MutableTerm &key,

lib/AST/RequirementMachine/EquivalenceClassMap.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ class EquivalenceClass {
8282
const MutableTerm &getKey() const { return Key; }
8383
void dump(llvm::raw_ostream &out) const;
8484

85+
bool hasSuperclassBound() const {
86+
return Superclass.hasValue();
87+
}
88+
8589
bool isConcreteType() const {
8690
return ConcreteType.hasValue();
8791
}

0 commit comments

Comments
 (0)