Introduce GenericSignature::requirementsNotSatisfiedBy(otherSig) to
compute the set of requirements in a generic signature that aren't satisfied
by some other generic signature. This is used both for conditional
conformances (the conditional requirements) and for name mangling of
constrained extensions/protocol conformances.
The mangler had some ad hoc logic for only mangling requirements in a
generic signature that are not requirements in the parent context's
generic signature. However, it was based on an heuristic that isn't
correct. Replace that logic with a check to determine whether
the requirement is satisfied by the parent generic signature, which is
far simpler.
Fixes rdar://problem/31889040 / SR-6107.
This allows determining which requirements make a conformance conditional; as
in, which requirements aren't known as part of the type itself.
Additionally, use this to assert that a few builtin protocols aren't
conditionally-conformed-to, something we won't support for now.
Now that the GenericSignatureBuilder is no longer sensitive to the input
module, stop uniquing the canonical GSBs based on that module. The main
win here is when deserializing a generic environment: we would end up
creating a canonical GSB in the module we deserialized and another
canonical GSB in the module in which it is used.
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()`.
Queries through the GenericSignatureBuilder about a particular type
parameter only really need information about the equivalence class in which that type parameter resides. Introduce a new entry point
GenericSignatureBuilder::resolveEquivalenceClass() that only
For now, resolveEquivalanceClass() is a thin layer over
resolveArchetype().
Use ArchetypeResolutionKind::CompleteWellFormed whenever we need to
ask questions about the potential archetype, and
ArchetypeResolutionKind::WellFormed when we need only evaluate whether
there is a legitimate type with that name (and possibly get a handle
to it).
Rather than pretend that the requirement signature of a protocol is a
full, well-formed generic signature that one can meaningfully query,
treat it as a flat set of requirements. Nearly all clients already did
this, but make it official. NFC
When a requirement signature could not be used to construct the
requirement sources in a conformance access path (due to recursive
protocols), we rebuild the path based on knowledge of the
protocol. Instead of using the requirement signature for this (which
depends on a canonicalized generic signature that breaks our intended
invariants w.r.t. unresolved nested types), use the protocol's generic
signature instead. This requires one small adjustment at the root of
the path, but is otherwise NFC.
Eliminates the penultimate use of AlwaysPartial.
When we infer a requirement from the result type of a function, don't
warn if that requirement was also stated explicitly. This has been a
point of confusion since we introduced the redundancy warnings,
because users don't consider to result type to be an "input" to the
function in the way the compiler does. So, while technically it is
"correct" to warn, it's unintuitive---so stop.
Fixes SR-5072 / rdar://problem/31357967.
When resolving archetypes using the "always partial" resolution kind,
we allow the system to form potential archetypes which might be
invalid. Start limiting the use of this "always partial" resolution
kind, so that it can eventually be removed entirely to simplify the
invariants of the GenericSignatureBuilder.
Each of the callers should either be working with complete,
well-formed archetypes or they should not force any resolution this
early.
Rather than having `ASTContext:: getOrCreateCanonicalGenericEnvironment()`
ask its `GenericSignatureBuilder` parameter recompute the generic signature
at nontrivial cost, just pass the known signature through.
SubstitutionMap::lookupConformance() would map archetypes out
of context to compute a conformance path. Do the same thing
in SubstitutionMap::lookupSubstitution().
The DenseMap of replacement types in a SubstitutionMap now
always has GenericTypeParamTypes as keys.
This simplifies some code and brings us one step closer to
a more efficient representation of SubstitutionMaps.
Rather than detecting recursion and bailing early, delay requirements
that would form recursive types. Note that we aren't actually
processing them later.
When a requirement mentions a concrete type, that type might utter
other types (e.g., Set<T>) that infer requirements (here, T:
Hashable). Perform requirement inference for such types.
Part of rdar://problem/31520386.
When asking a substitution map for a conformance, it's okay if the
conformance isn't there---just detect this case and return None.
Also, collapse a redundant testcase Huon noted.
When looking for a conformance for an archetype, map it out of context
to compute the conformance access path, then do the actual lookups
based on mapping the starting type back into the context. Eliminate
the parent map and "walk the conformances" functionality.
Substitution maps are effectively tied to a particular generic
signature or environment; keep track of that signature/environment so
that we can (eventually) use it to find conformances.
Move the storage for the protocols to which a particular potential
archetype conforms into EquivalenceClass, so that it is more easily
shared. More importantly, keep track of *all* of the constraint
sources that produced a particular conformance requirement, so we can
revisit them later, which provides a number of improvements:
* We can drop self-derived requirements at the end, once we've
established all of the equivalence classes
* We diagnose redundant conformance requirements, e.g., "T: Sequence"
is redundant if "T: Collection" is already specified.
* We can choose the best path when forming the conformance access
path.
Requirement signatures are a bit brittle, because they (intentionally)
don't carry the "Self: Proto" requirement. Most of the compiler never
uses requirement signatures as a signature per se, which is good,
because they canonicalize poorly.
Teach the construction of conformance access paths to use the
protocol's generic signature for canonicalization, rather than the
requirement signature.
As a future step, we should present only the *requirements* from the
requirement signature to prevent its use as a full-fledged
GenericSignature.
When a requirement source involving a ProtocolRequirement element is
built prior to the requirement signature of the protocol it
references, we can end up with a requirement source whose steps don't
reflect was is actually available via the requirement signatures. When
building a conformance access path from such requirement sources,
canonicalize on-the-fly using the requirement signatures (which have
been/can be computed by this point) to produce a correct access path.
Introduce an API that determines the "conformance access path" that
one would follow to find the conformance of a given type parameter
(e.g., T.Iterator.Element) to a given protocol (e.g., Equatable). A
conformance access path starts at one of the explicit requirements
of that generic signature and then proceeds through zero or more
protocol-supplied requirements. For example, given this function:
func f<C: Collection>(_: C) { }
The conformance access path for "C.Iterator: IteratorProtocol" is
(C, Collection) -> (Self, Sequence) -> (Self.Iterator, IteratorProtocol)
because one starts with the explicit requirement "C: Collection", goes
to the inherited protocol requirement (the "Self" in Collection
conforms to Sequence) and then a requirement on the associated type
(Self.Iterator in Sequence conforms to IteratorProtocol).
This is all scaffolding now; it's intended to be used by IRGen (to
find the witness tables it needs) and SubstitutionMap (to dig out
conformances during substitution).
This was a remnant of the old generics implementation, where
all nested types were expanded into an AllArchetypes list.
For quite some time, this method no longer returned *all*
dependent types, only those with generic requirements on
them, and all if its remaining uses were a bit convoluted.
- In the generic specialization code, we used this to mangle
substitutions for generic parameters that are not subject
to a concrete same-type constraint.
A new GenericSignature::getSubstitutableParams()
function handles this use-case instead. It is similar
to getGenericParams(), but only returns generic parameters
which require substitution.
In the future, SubstitutionLists will only store replacement
types for these generic parameters, instead of the list of
types that we used to produce from getAllDependentTypes().
- In specialization mangling and speculative devirtualization,
we relied on SubstitutionLists having the same size and
order as getAllDependentTypes(). It's better to turn the
SubstitutionList into a SubstitutionMap instead, and do lookups
into the map.
- In the SIL parser, we were making a pass over the generic
requirements before looking at getAllDependentTypes();
enumeratePairedRequirements() gives the correct information
upfront.
- In SIL box serialization, we don't serialize the size of the
substitution list, since it's available from the generic
signature. Add a GenericSignature::getSubstitutionListSize()
method, but that will go away soon once SubstitionList
serialization only serializes replacement types for generic
parameters.
- A few remaining uses now call enumeratePairedRequirements()
directly.
When enumerating "paired" requirements, we were failing to drop some
generic type parameters that have concrete bindings. Drop all of them
consistently.
Make the addSubstitution() and addConformance() methods private,
and declare GenericEnvironment and GenericSignature as friends of
SubstitutionMap.
At some point in the future, we can switch to a more efficient
representation of SubstitutionMap, where instead of storing
multiple hashtables, we store arrays; the keys are pre-determined.
Remove the pre-expansion of all of the archetypes in a generic
environment; they can be constructed lazily from interface types.
Note that this only concerns the construction of the archetypes
themselves. The archetype builder is still pre-expanding all
*potential* archetypes.
"Fixes" rdar://problem/30351514, in the sense that the eager code and
the assertion that was getting tripped up are being eliminated
completely.
These are no longer necessary now that we have combineSubstitutionMaps(),
and will not make sense once we switch to a more compact representation
for SubstitutionMap.
SubstitutionList is going to be a more compact representation of
a SubstitutionMap, suitable for inline allocation inside another
object.
For now, it's just a typedef for ArrayRef<Substitution>.