If the class itself is generic and we're looking up a nested type
from a conformance, we would pass an interface type to
mapTypeOutOfContext() and crash.
Once we compute a generic signature from a generic signature builder,
all queries involving that generic signature will go through a separate
(canonicalized) builder, and the original builder can no longer be used.
The canonicalization process then creates a new, effectively identical
generic signature builder. How silly.
Once we’ve computed the signature of a generic signature builder, “register”
it with the ASTContext, allowing us to move the existing generic signature
builder into place as the canonical generic signature builder. The builder
requires minimal patching but is otherwise fully usable.
Thanks to Slava Pestov for the idea!
This is somewhat of a pyrrhic victory, because it was just a shell over
resolvePotentialArchetype() anyway, but we now have fewer entry points that
produce potential archetypes.
Use resolveEquivalenceClass() instead, which will be more lightweight in the
future. This is effectively NFC because we were already alway working on
the representatives of the equivalence classes in this code.
We shouldn’t need a potential archetype to map an interface type to a
contextual type. Port `getTypeInContext()` over to `EquivalenceClass`,
largely unchanged, so we don’t directly form archetypes.
Kills a few more uses of `GenericSignatureBuilder::resolveArchetype()`.
The anchor of an equivalence class canonically represents that equivalence
class. Add API for computing the anchor directly, and switch a few more
clients off of `resolveArchetype()`.
Funnel all places where we create a generic signature builder to compute
the generic signature through a single entry point in the GSB
(`computeGenericSignature()`), and make `finalize` and `getGenericSignature`
private so no new uses crop up.
Tighten up the signature of `computeGenericSignature()` so it only works on
GSB rvalues, and ensure that all clients consider the GSB dead after that
point by clearing out the internal representation of the GSB.
We had two similar loops that performed name lookup for nested types on a
potential archetype, so consolidate those into a single implementation on
the equivalence class itself.
RequirementSources, PotentialArchetypes, and EquivalenceClasses live as
long as the GenericSignatureBuilder. BumpPtrAllocate them all, introducing
a free list for equivalence classes because those can be transient.
Managing equivalence classes via the implicit structure of potential
archetypes is silly, and leads to weird patterns where we visit all
potential archetypes just to find the equivalence classes. Teach the
GSB implementation to manage equivalence classes in a linked list, so we
can easily iterate over them, and switch most uses of
`visitPotentialArchetypes()` over to that iteration.
Funnel all places where we create a generic signature builder to compute
the generic signature through a single entry point in the GSB
(`computeGenericSignature()`), and make `finalize` and `getGenericSignature`
private so no new uses crop up.
Tighten up the signature of `computeGenericSignature()` so it only works on
GSB rvalues, and ensure that all clients consider the GSB dead after that
point by clearing out the internal representation of the GSB.
We had two similar loops that performed name lookup for nested types on a
potential archetype, so consolidate those into a single implementation on
the equivalence class itself.
Once we compute a generic signature from a generic signature builder,
all queries involving that generic signature will go through a separate
(canonicalized) builder, and the original builder can no longer be used.
The canonicalization process then creates a new, effectively identical
generic signature builder. How silly.
Once we’ve computed the signature of a generic signature builder, “register”
it with the ASTContext, allowing us to move the existing generic signature
builder into place as the canonical generic signature builder. The builder
requires minimal patching but is otherwise fully usable.
Thanks to Slava Pestov for the idea!
Funnel all places where we create a generic signature builder to compute
the generic signature through a single entry point in the GSB
(`computeGenericSignature()`), and make `finalize` and `getGenericSignature`
private so no new uses crop up.
Tighten up the signature of `computeGenericSignature()` so it only works on
GSB rvalues, and ensure that all clients consider the GSB dead after that
point by clearing out the internal representation of the GSB.
We had two similar loops that performed name lookup for nested types on a
potential archetype, so consolidate those into a single implementation on
the equivalence class itself.
When computing the requirement signature of a protocol, eliminate requirement
sources that are self-derived by virtual of using a given requirement of
that protocol to prove that same constraint.
When there are to "structurally" equivalent potential archetypes in
different components of an equivalence class, as determined by their
nested-name structure, collapse the two components. This addresses the
remaining known issues due to the eager explosion of potential
archetypes in the generic signature builder.
Same-type constraints are rederived based on the potential archetypes
within an equivalence class and the same-type constraints that link
them. In some cases, there may be parts that connect those same-type
constraints that are stored in "delayed" requirements (for which one
or both end-points have not been realized in a potential archetype);
consider those as well for connectedness.
In a sense, this is an artifact of the generic signature builder's
approach of realizing potential archetypes too readily, and this can
likely be simplified in the future. For now, it's important for the
minimization of same-type constraints in generic signatures.
Nested-type-name-match constraints are odd because they are
effectively artifacts of the GenericSignatureBuilder's algorithm,
i.e., they occur when we have two PotentialArchetypes representing the
same type, and each of those PA's has a nested type based on the same
associated type. Because of this, nested-type-name-match constraints
have no useful requirement sources, so the normal means of detecting
self-derived constraints doesn't suffice, and we end up with
self-derived nested-type-name-match constraints eliminating the
constraints they depend on, causing spurious "redundant same-type
constraint" diagnostics and minimized generic signatures that drop
important requirements.
Handle nested-type-name-match constraints by first keeping them out of
the connected-components algorithm used to compute same-type
constraints within an equivalence class. Then, detect self-derived
nested-type-name-match constraints by determining whether any of the
ancestor potential archetypes are in the same equivalence class... and
redundant with the edge that makes the ancestor potential archetypes
equivalent. Remove such self-derived edges, and treat all other
nested-type-name-match edges as derived, providing a minimized
signature.
Fixes SR-5841, SR-5601, and SR-5610
When we have two nested types of a given potential archetype that have
the same name, introduce a (quietly) inferred constraint. This is
a future-proofing step for canonicalization, for a possible future
where we no longer require all of the nested types of a given name
to be equivalent, e.g., because we have a proper disambiguation
mechanism.