This will replace the 'concrete type in domain' hack. Instead of
finding some other type parameter with the same concrete type and a
compatible starting symbol, this finds a prefix of the original
term. This allows the induced same-type requirement to be described
with a rewrite path.
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.
A superclass requirement 'T : C' implies a layout requirement
'T : AnyObject' (if the class is @objc) or 'T : _NativeObject'
(if the class is not @objc).
In the latter case, there might already be a 'T : AnyObject'
requirement, in which case the type parameter 'T' is subject
to two layout requirements:
T : AnyObject
T : _NativeObject
The second requirement implies the first however. To encode this
in the world of rewrite loops, we the notion of a 'relation'
between property symbols, and a 'Relation' rewrite step.
Here, the relation is that _NativeObject < AnyObject. Once this
relation is recorded, the Relation rewrite step will transform
T.[layout: _NativeObject].[layout: AnyObject]
into
T.[layout: _NativeObject]
and vice versa.
This rewrite step allows us to construct a rewrite loop which
makes the first rewrite rule redundant via the second.
Using the qualified name is subtly different from scoping the function.
Use the latter, which correctly places the function into the namespace,
to enable building with VS2022.
First pass:
- Eliminate rules with unresolved name symbols in LHS
- Eliminate simplified non-conformance rules
Second pass:
- Eliminate non-minimal conformance rules
Third pass:
- Eliminate all other non-conformance rules
If you have a concrete requirement with a non-canonical substitution, like
A : P, A == G<B.T>
We add an induced rule for the abstract type witness,
A.T == B.T
This rule has a rewrite path in terms of the previous two rules, but we
want to try to eliminate the other two rules first.
This new ordering ensures we eliminate the simplified rule A == G<B.T> and
compute minimal conformances before we get around to considering A.T == B.T,
which can no longer be eliminated by that point.
If we eliminate A.T == B.T first, we end up with simplified concrete
type and concrete conformance rules which cannot be eliminated:
A.[concrete: G<B.T>] => A
A.[concrete: G<B.T> : P] => A
This changes the minimized signature in an incompatible way in two test cases.
In Generics/rdar83308672.swift, the signature becomes equivalent to what the
GSB used to output.
In Generics/sr10532.swift, the GSB would output an invalid signature anyway,
so it doesn't matter.
We would bail out early if there was no property map entry for this key.
But this means if a term without properties was non-canonical, this
method would still return false.
On the other hand, it is possible for a DependentMemberType to be
canonical, even if its parent is not, in the case where the parent
is fixed to a concrete type.
To handle this properly, change the type walk to use a TypeWalker
directly instead of findIf(); this allows us to return
Action::SkipChildren upon encountering a DependentMemberType.
The primary use of isCanonicalTypeInContext() was from inside
GenericSignature::verify(). So the assertion there will become
stricter.