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.
Define the relation as
[concrete: C].[P] =>> [concrete: C].[concrete: C : P]
instead of
[concrete: C].[P] =>> [concrete: C : P]
This changes the rewrite loop recorded for a rule T.[concrete: C : P]
to have (T.[concrete: C] => T) appearing twice in context instead of
just once.
We don't ever want a concrete conformance rule to be able to imply a
concrete type rule. This became possible with loop normalization
because the single occurrence of (T.[concrete: C] => T).[P] could
cancel with a subsequent step (T => T.[concrete: C]).[P] in another
rewrite loop after substitution.
Distinguish a loop with elimination candidates, which are rules
appearing in empty context and exactly once, from a useful loop,
which contains at least one rule in empty context (but the same
rule might appear more than once).
Normalizing a useful loop might produce a loop with elimination
candidates, but normalizing a useless loop never does.
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.
- Allow duplicate concrete type and superclass requirements on the
same generic parameter, as long as they're identical. This can
arise if requirement inference infers a requirement which the
user then explicitly re-states.
- If duplicate requirements are found that name different types, drop
only that generic parameter from consideration without giving up
entirely.
- If a generic parameter is subject to both a concrete type and a
superclass requirement, proceed with the concrete type requirement
since it is more specific instead of giving up.
Previously only the GenericSignatureBuilder would call this; to ensure
we get the same test coverage when the Requirement Machine is 'on' as
'verify', also call this from the Requirement Machine.
For now, we can't call this from RequirementSignatureRequestRQM due
to circularity issues; that will have to wait until this request is
folded into RequirementSignatureRequest.
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.
See the comment at the top of ConcreteContraction.cpp for a detailed explanation.
This can be turned off with the -disable-requirement-machine-concrete-contraction
pass, mostly meant for testing. A few tests now run with this pass both enabled
and disabled, to exercise code paths which are otherwise trivially avoided by
concrete contraction.
Fixes rdar://problem/88135912.
The conflicting rule here is the permanent 'identity conformance'
([P].[P] => [P]). Permanent rules cannot be marked as conflicting,
so just check for this condition first.
If you have something like this:
protocol P {
associatedtype A : Q where Self == Self.A.B
}
protocol Q {
associatedtype B
}
class C : P {
typealias A = D
}
class D : P {
typealias B = C
}
The GSB would minimize the generic signature <T where T : P, T : C>
to <T where T == C>, because of the same-type requirement in
protocol P.
However in reality, the conformance 'C : P' is unsound, because it
is no longer covariant. I added a warning in commit d831eff74879cb.
Because the upcoming 'concrete contraction' pass eliminates 'T : P'
before homotopy reduction gets a chance to run, I'm changing the
Requirement Machine to produce a different minimization from the
GSB. This is technically an ABI break, but it should not impact any
real code in practice. If it does, I'll need to come up with a
different workaround in concrete contraction.
We want to prefer explicit rules when an explicit rule and non-explicit
rule conflict. Since the explicit bit hasn't been computed yet when
building the property map, save conflicting rule pairs in a side table,
and then process them later in homotopy reduction.
The side table will also be useful for diagnostics later.
This ensures we produce the same minimal signature as the GSB
in a couple of really silly examples where a superclass requirement
and a concrete type requirement imply each other.
Instead of keeping track of the best one so far, and unifying subsequent rules
against it.
This allows us to record more identities, fixing a regression from an earlier
change where we were unable to eliminate an obviously-redundant rule.