RequirementMachine: Refine 'derived via protocol typealias' criterion

Preserves concrete type rules on associated types that were derived
from rules indirectly formed from protocol typealias rules.

That is, if you have a pair of rules in another minimization domain:

    [P].A.[concrete: C] => [P].A
    [Q:T].[P] => [Q:T]

Then completion will introduce a new rule:

    [Q:T].A.[concrete: C] => [Q:T].A

Since this rule is outside of our minimization domain, we don't record
a rewrite loop for it, and it will never become redundant.

Now if we have a rule in our own minimization domain:

    T.[Q:T].A => T.[Q:U]

Then we get a new rule:

    T.[Q:U].[concrete: C] => T.[Q:U]

Make sure we keep this rule around on account of it being derived from
([Q:T].A.[concrete: C] => [Q:T].A).
This commit is contained in:
Slava Pestov
2022-03-11 21:20:21 -05:00
parent 3576318fc7
commit 762bf1e7d0
4 changed files with 28 additions and 4 deletions

View File

@@ -193,6 +193,29 @@ Optional<Identifier> Rule::isProtocolTypeAliasRule() const {
return LHS[1].getName();
}
/// A rule was derived from a concrete protocol typealias if it
/// takes the following form:
///
/// T.A.[concrete: C] => T.A
///
/// Where the prefix term T does not contain any name symbols, and
/// A is a name symbol.
bool Rule::isDerivedFromConcreteProtocolTypeAliasRule() const {
auto optSymbol = isPropertyRule();
if (!optSymbol || optSymbol->getKind() != Symbol::Kind::ConcreteType)
return false;
for (unsigned i = 0, e = RHS.size() - 1; i < e; ++i) {
if (RHS[i].getKind() == Symbol::Kind::Name)
return false;
}
if (RHS.back().getKind() != Symbol::Kind::Name)
return false;
return true;
}
/// Returns the length of the left hand side.
unsigned Rule::getDepth() const {
auto result = LHS.size();