When looking up a conformance in a substitution map, check whether
there is a superclass constraint that satisfies the conformance. If
so, use it directly rather than going through a slower path to find
it.
Addresses rdar://problem/46655186.
The former appears in the code base a lot more frequently than the
latter, which returns a GenericTypeParamType *. Use it only in places
where the more specific type is intended.
Instead of using the callback form of SubstitutionMap::get(), let's
use the lower-level form that takes the replacement array and
conformances array directly, allowing us to bypass several
calls of subst() on 'this'.
- getAsDeclOrDeclExtensionContext -> getAsDecl
This is basically the same as a dyn_cast, so it should use a 'getAs'
name like TypeBase does.
- getAsNominalTypeOrNominalTypeExtensionContext -> getSelfNominalTypeDecl
- getAsClassOrClassExtensionContext -> getSelfClassDecl
- getAsEnumOrEnumExtensionContext -> getSelfEnumDecl
- getAsStructOrStructExtensionContext -> getSelfStructDecl
- getAsProtocolOrProtocolExtensionContext -> getSelfProtocolDecl
- getAsTypeOrTypeExtensionContext -> getSelfTypeDecl (private)
These do /not/ return some form of 'this'; instead, they get the
extended types when 'this' is an extension. They started off life with
'is' names, which makes sense, but changed to this at some point. The
names I went with match up with getSelfInterfaceType and
getSelfTypeInContext, even though strictly speaking they're closer to
what getDeclaredInterfaceType does. But it didn't seem right to claim
that an extension "declares" the ClassDecl here.
- getAsProtocolExtensionContext -> getExtendedProtocolDecl
Like the above, this didn't return the ExtensionDecl; it returned its
extended type.
This entire commit is a mechanical change: find-and-replace, followed
by manual reformatted but no code changes.
When we compute a replacement type for a non-substitutable generic
parameter, canonicalize the type when our generic signature is
canonical. This ensures that the canonical substitution map will
have canonical types for all of the replacement types… including those
for non-substitutable generic parameters that aren’t part of the
FoldingSet profile.
SubstitutionMaps are now just a trivial pointer-sized value, so
pass them by value instead.
I did have to move a couple of functors from Type.h to SubstitutionMap.h
to resolve some issues with forward declarations.
This is much easier to read when part of a larger dump, where it now occurs in
expressions and specialized conformances.
Part of rdar://problem/40074968.
When forming a substitution map from a type substitution function and
conformance lookup function, we were calling the type substitution function
for generic parameters that aren't canonical (e.g., because they are
same-typed to something else). The type substitution functions wouldn't
necessarily take the new generic signature into account, so we would get
incorrect replacement types.
Detect non-canonical generic parameters when forming substitution maps,
and leave those entries in the "replacements" array blank; we'll fill them
in later, properly, when needed.
Introduced during the bring-up of the generics system in July, 2012,
Substitution (and SubstitutionList) has been completely superseded by
SubstitutionMap. R.I.P.
Introduce an operation to check that a given substitution map is non-empty
(i.e., corresponds to a generic signature) and that the generic signature
has type parameters that aren’t bound to concrete types. This is the
appropriate predicate for SIL-and-later to determine whether there
will be any substitutions.
SubstitutionMap::lookupSubstitution() assumed that any type parameter it was
given would already be canonical, and fail (return a null Type) when given
a type parameter that was equivalent to another type parameter but is
not itself canonical. Canonicalize, recursive, and record the replacement
type appropriately.
Every SubstitutionMap::toList() invocation would ASTContext-allocate
arrays for all of the conformances, then return a SmallVector of the
underlying substitutions, which both wastes memory *and* puts the onus
on the caller to allocate a copy of that outer SmallVector into the
ASTContext if it's going to be stored anywhere.
Stop the madness by caching an ASTContext-allocated SubstitutionList
within the storage for the SubstitutionMap. This both reduces repeated
allocations and eliminates the potential for errors.
Now that SubstitutionMap is used in so many places, reduce it's header
dependencies by moving SubstitutionMap::Storage into its own separate
implementation header. Use forward declarations of other entities
(GenericSignature, Substitution) instead.
Good for build times and general sanity.
Replace two prominent uses of SubstitutionList, in ConcreteDeclRef and
Witness, with SubstitutionMap. Deal with the myriad places where we
now have substitution maps and need substitution lists (or vice versa)
caused by this change.
Overall, removes ~50 explicit uses of SubstitutionList (of ~400).
Prepare for SubstitutionMaps to be stored in other AST nodes by making
them ASTContext-allocated and uniqued (via a FoldingSet). They are now
cheap to copy and have trivial destructors.
Collapse the out-of-line array of replacement types and the DenseMap used
for conformances into a single field that references out-of-line,
tail-allocated storage for all of the contents of a SubstitutionMap.
The conformances are now represented as a flat array whose indices
line up with the indices of the conformance requirements in the
underlying generic signtature.
Reference this storage via a single shared_ptr, so that copies of
SubstitutionMaps are cheap but we aren't (yet) uniqueing them or
storing them within the ASTContext.
The primary implementation for substituting into substitution maps was
cloning the contents of the SubstitutionMap and then performing
in-place updates to the (new) data structure, which both had too many
dependencies on the data structure and subverted some of the checking
we get through the normal path.
Reimplement this function in terms of
GenericSignature::getSubstitutionMap(), which is the primary/canonical
way to form a substitution map.
The generic signature used to perform substitutions for a BoundNameAliasType
in ill-formed code might not line up with the generic signature in the
typealias. Separately record the signature we used to build the
BoundNameAliasType to make the AST more robust against such issues.
Introduce a new Type node, BoundNameAliasType, which describes a
reference to a typealias that requires substitutions to produce the
underlying type. This new type node is used both for references to
generic typealiases and for references to (non-generic) typealiases
that occur within generic contexts, e.g., Array<Int>.Element.
At present, the new type node is mainly useful in preserving type
sugar for diagnostics purposes, as well as being reflected in other
tools (indexing, code completion, etc.). The intent is to completely
replace NameAliasType in the future.
Conformances that discoverably for a type parameter via a superclass
requirement occupy a bit of a gray area in the type checker and
generic signature handling right now: we have a type parameter (so the
paths that handle concrete conformances don't kick in), but the
conformance itself isn't modeled as a requirement because it is
available via lookup. Teach SubstitutionMap's conformance lookup to
detect this case and perform conformance lookup in the generic
signature (i.e., falling back to global lookup) in this case,
replicating the hack that IRGen uses to address the same issue when
accessing the conformance (see GenArchetype.cpp's TODO where we lookup
a conformance on the superclass). The removal of that hack (as well as
this one) are tracked by rdar://problem/34609744.
For now, fixes SR-7072 / rdar://problem/37904576.
This will allow key paths to resiliently reference public properties from other binaries by referencing a descriptor vended by the originating binary. NFC yet, this just provides printing/parsing/verification of the new component.
The enclosing conformance-lookup operation can fail (i.e., it returns
Optional), but the nested call was force-unwrapping the optional from
an inner call for no particular reason. Stop doing that, which fixes
SR-6466.
Note that the offending code is still something that should go away in
time, so this is merely polishing the band-aid to avoid a crash that
occurs often with conditional conformances.
If there's no lazy resolver and we're looking at an incomplete conformance,
fail with an error instead of crashing. The caller will likely crash also,
but at least this allows better recovery in this case in the future.