initialization of the rewrite system.
Instead, the rewrite system can determine trivially redundant requirements
by finding structural requirements with no associated rewrite rules.
rule has a non-explicit, non-redundant rule in its rewrite path.
This fixes bogus redundancy diagnostics in cases where the canonical form
of a redundant rule is not explicit in source, e.g.
protocol Swappable2 {
associatedtype A
associatedtype B
associatedtype Swapped : Swappable2
where Swapped.B == A,
Swapped.Swapped == Self
}
in the above case, the canonical rule for `Swapped.B == A` is the rule
[Swappable2:Swapped].[Swappable2:A] => [Swappable2:B], which is not
explicit.
rules in a separate pass after homotopy reduction.
RewriteSystem::propagateExplicitBits was too eager in propagating
IDs from explicit rules within rewrite loops, which resulted in bogus
redundancy warnings when the canonical form of an explicit rule was
given a different requirement ID. Instead, propagate requirement IDs
after homotopy reduction when redundant rules are computed and rewrite
loops are simplified.
rewrite system.
This ID can be used to index into the WrittenRequirements array in the
rewrite system to retrieve the structural requirement, e.g. for the
purpose of diagnostics.
These rules would be fine since RHS simplification eliminates them,
but they cause problems for the minimal conformances algorithm.
To avoid introducing such rules, ensure that the critical pair of
two property-like rules is itself a property-like rule instead of
relying on subsequent simplifications sorting it out. See the
new comment in RewriteSystem::computeCriticalPair() for details.
I need to understand this problem better and either fix minimal
conformances or add stronger assertions, but for now this fixes
the last failure with -requirement-machine-abstract-signatures=verify.
Consider this example:
protocol P : C {}
class C : P {}
<T where T : P>
The GenericSignatureBuilder thinks the minimized signature is
<T where T : P>. The RequirementMachine would minimize it down to
<T where T : C>. The latter is more correct, since the conformance
here is concrete and no witness table needs to be passed in at
runtime, however for strict binary compatibility we need to produce
the same signature as the GenericSignatureBuilder.
Accomplish this by changing the minimal conformances algorithm to
detect "circular concrete conformance rules", which take the form
[P].[concrete: C : Q]
Where Q : P. These rules are given special handling. Ordinarily a
protocol conformance rule is eliminated before a concrete conformance
rule; however concrete conformances derived from circular
conformances are considered to be redundant from the get-go,
preventing protocol conformances that can be written in terms of
such concrete conformances from themselves becoming redundant.
Fixes rdar://problem/89633532.
There are two kinds of protocol typealiases:
1) The underlying type is a type parameter. These rules look like
[P].A => X where X is the underlying type.
2) The underlying type is a concrete type. These rules look like
[P].A.[concrete: C] => [P].A.
The isProtocolTypeAliasRule() predicate detects both cases and
returns the type alias name ('A', in the above examples). For now
it's not used anywhere, since we don't actually introduce these
rules for any reason.
We used to skip a pass if any of the three flags were set, but we have
to check them separately to ensure that all flags are independently
set correctly.
We have three simplification passes, give each one its own predicate:
- Left hand side simplification
- Right hand side simplification
- Substitution simplification
This is for debugging output and will also allow me to tighten up
some invariants.
When minimizing a generic signature, we only care about loops
where the basepoint is a generic parameter symbol.
When minimizing protocol requirement signatures in a connected
component, we only care about loops where the basepoint is a
protocol symbol or associated type symbol whose protocol is
part of the connected component.
All other loops can be discarded since they do not encode
redundancies that are relevant to us.
Previously we did this when adding new concrete type rules,
but we don't have a complete rewrite system at that point yet,
so there was no guarantee concrete substitution terms would
be canonical.
Now, perform simplification in a post-pass after completion,
at the same time as simplifying rule right hand sides.
Rewrite loops are recorded relating the original rule with the
simplified substitutions.
With this change the RequirementMachine's minimization behavior with
protocol refinement rules matches the GenericSignatureBuilder.
See https://github.com/apple/swift/pull/37466 for a full explanation
of what's going on here.
A superclass requirement implies a layout requirement. We don't
want the layout requirement to be present in the minimal
signature, so instead of adding a pair of requirements:
T.[superclass: C<X, Y>] => T
T.[layout: _NativeClass] => T
Add this pair of requirements:
T.[superclass: C<X, Y>] => T
[superclass: C<X, Y>].[layout: _NativeClass] => [superclass: C<X, Y>] [permanent]
Completion then derives the rule as a consequence:
T.[layout: _NativeClass] => T
Since this rule is a consequence of the other two rules, homotopy
reduction will mark it redundant.