initialization of the rewrite system.
Instead, the rewrite system can determine trivially redundant requirements
by finding structural requirements with no associated rewrite rules.
- Rename StepLimit to MaxRuleCount, DepthLimit to MaxRuleLength
- Rename command line flags to -requirement-machine-max-rule-{count,length}=
- Check limits outside of PropertyMap::buildPropertyMap()
- Simplify the logic in RequirementMachine::computeCompletion()
Conditional requirement inference needs to be able to add rewrite rules
from the requirement signatures of hitherto-unseen protocols, so to
help with that, extract out the RuleBuilder's ProtocolMap and move it
into the RewriteSystem.
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.
We assert when building a rewrite system for an existing generic
signature, or in AbstractGenericSignatureRequest, where there is no
source location.
In RequirementSignatureRequest and InferredGenericSignatureRequest
we now produce a diagnostic.
This is a source-level error, not an invariant violation. Instead, plumb
a new hadError() flag, which in the future will assert if no diagnostic
was produced.
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.
Now that the property map stores a reference to the RewriteSystem,
defining the buildPropertyMap() method on PropertyMap feels cleaner,
and allows more of the property map's internals to be private.
Completion adds this rule when a same-type requirement equates the Self of P
with some other type parameter conforming to P; one example is something like this:
protocol P {
associatedtype T : P where T.T == Self
}
The initial rewrite system looks like this:
(1) [P].T => [P:T]
(2) [P:T].[P] => [P:T]
(3) [P:T].[P:T] => [P]
Rules (2) and (3) overlap on the term
[P:T].[P:T].[P]
Simplifying the overlapped term with rule (2) produces
[P:T].[P:T]
Which further reduces to
[P]
Simplifying the overlapped term with rule (3) produces
[P].[P]
So we get a new rule
[P].[P] => [P]
This is not a "real" conformance rule, and homotopy reduction wastes work
unraveling it in rewrite loops where this rule occurs. Instead, it's better
to introduce it as a permanent rule that is not subject to homotopy reduction
for every protocol.
Also while plumbing this through, don't record homotopy generators
unless we're minimizing a protocol signature, since they're not
used for anything else yet.
When using the requirement machine to build protocol signatures,
we can't get the protocol's dependencies by looking at the
conformance requirements in it's requirement signature, because
we haven't computed the requirement signature yet.
Instead, get the dependencies via the recently-added
getStructuralRequirements() request.
- Skip permanent rules (there's no point, we'll add them back next time)
- Skip conformance rules (these will be handled separately)
- Delete 3-cells that are entirely "in-context" (but don't quote me on
this one, I'm not quite yet convinced it's correct, but it feels right)