When an archetype conforms to a protocol abstractly (ie, it is
not class-constrained and we don't have any further information
other than that it conforms), we can recover nested types,
but we cannot recover the conformance of those nested types
to protocols if those conformances are concrete (the nested
type might be concrete, or it might be a class-constrained
archetype).
To work around this, we added a hack where if the conformance
lookup in the SubstitutionMap fails, we fall back to the module.
This is horrible and unprincipled, but has to remain in place
until more infrastructure is plumbed through.
Commit 620db5f74c made this
workaround apply in fewer cases, so that we could still catch
cases where the SubstitutionMap was constructed with missing
conformances.
Unfortunately this workaround didn't handle the case where the
nested type was an archetype with a superclass constraint.
This will all go away soon, but for now tweak the logic a bit,
since I really want to keep the "narrow" workaround in place
and not the general fallback, otherwise we run the risk of
SubstitutionMap conformance lookup bitrotting completely.
Fixes <https://bugs.swift.org/browse/SR-4088> and
<rdar://problem/32773028>.
The replacement types in a SubstitutionMap correspond with the generic
parameters of its generic signature, so replace the DenseMap storage
with a flat array of Types, one element for each generic parameter.
If SubstitutionMap is asked to form a substitution for a generic
parameter that has been made concrete by the generic signature,
substitute into the concrete type. This allows us to better deal with
non-canonical types.
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.
This manifested as test/Prototypes/PatternMatching.swift failing
under 'ninja check-swift-validation-optimize'.
I'll add a test later if I have time to reduce a test case, but this
whole hack is hopefully going away soon anyway.
Fixes one of the three failures outlined in <rdar://problem/31780356>.
Instead of just falling back to module lookup any time conformance
substitution fails, only do it in the case we know doesn't work.
This should shake out some more bugs, hopefully without causing
too much pain.
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.
When looking up a particular conformance in a SubstitutionMap, use the
associated generic signature to determine how to find that conformance
(via a conformance access path). Follow that conformance access path
to retrieve the desired conformance.
FIXME: There is still one failure, here
Constraints/generic_overload.swift
which appears to be because we either have the wrong generic signature
for the override case or we are looking in the wrong map.
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.
We go to look at the conforming protocols of an associated type
but we haven't built the generic environment for the associated
type's protocol yet.
In the test case given, we find the conformance later via a
different path, so everything continues to work.
SubstitutionMap::lookupConformance() is hopefully getting a
makeover soon, and this hack will go away.
Fixes <rdar://problem/31302713>.
We should enable it again once the substitutions machinery and GenericSignatureBuilder always generate correct SubstitutionMaps.
But for now let’s disable it to unblock the CI jobs.
Should fix SR-4322 and rdar://31224655
The list of directly inherited protocols of a ProtocolDecl is already
encoded in the requirement signature, as conformance constraints where
the subject is Self. Gather the list from there rather than separately
computing/storing the list of "inherited protocols".
If a protocol appears inside a generic context, the Self parameter
will not be the only generic parameter; outer generic parameters
will be part of the protocol's signature also.
Change the asserts in getProtocolSubstitutions() to return error
types instead in this case.
A new SubstitutionMap::getProtocolSubstitutions() method handles
the case where we construct a trivial SubstitutionMap to replace
the protocol Self type with a concrete type.
When substituting one opened existential archetype for another,
use the form of Type::subst() that takes two callbacks instead of
building a SubstitutionMap. SubstitutionMaps are intended to be
used with keys that either come from a GenericSignature or a
GenericEnvironment, so using them to replace opened archetypes
doesn't fit the conceptual model we're going for.
In several places, we construct a SubstitutionMap by taking
generic parameters from one SubstitutionMap up to a certain
depth, with the rest coming from a second SubstitutionMap.
Factor this out into a new utility method, to help with
hiding the internal representation of SubstitutionMap from
clients.
This was meant to be NFC, but it actually fixes a crash in
the devirtualizer, because the old logic there was slightly
wrong, so I added a test for this.
First, add some new utility methods to create SubstitutionMaps:
- GenericSignature::getSubstitutionMap() -- provides a new
way to directly build a SubstitutionMap. It takes a
TypeSubstitutionFn and LookupConformanceFn. This is
equivalent to first calling getSubstitutions() with the two
functions to create an ArrayRef<Substitution>, followed by
the old form of getSubstitutionMap() on the result.
- TypeBase::getContextSubstitutionMap() -- replacement for
getContextSubstitutions(), returning a SubstitutionMap.
- TypeBase::getMemberSubstitutionMap() -- replacement for
getMemberSubstitutions(), returning a SubstitutionMap.
With these in place, almost all existing uses of subst() taking
a ModuleDecl can now use the new form taking a SubstitutionMap
instead. The few remaining cases are explicitly written to use a
TypeSubstitutionFn and LookupConformanceFn.
Conformances for an associated type might be attached to any
same-named associated type of the parent, so search those as
well. Overally, this is a fairly expensive search, and there is likely
a better architectural solution that will require some refactoring of
SubstitutionMap.
When enumerating requirements, always use the archetype anchors to
express requirements. Unlike "representatives", which are simply there
to maintain the union-find data structure used to track equivalence
classes of potential archetypes, archetype anchors are the
ABI-stable canonical types within a fully-formed generic signature.
The test case churn comes from two places. First, while
representatives are *often* the same as the archetype anchors, they
aren't *always* the same. Where they differ, we'll see a change in
both the printed generic signature and, therefore, it's
mangling.
Additionally, requirement inference now takes much greater
care to make sure that the first types in the requirement follow
archetype anchor ordering, so actual conformance requirements occur in
the requirement list at the archetype anchor---not at the first type
that is equivalent to the anchor---which permits the simplification in
IRGen's emission of polymorphic arguments.
We were dropping the substitutions required to call the default
argument generator on the floor, when the correct solution is to
remap them to substitutions in terms of the base class signature.
Fixes <rdar://problem/29721571>.
Type substitution works on a fairly narrow set of types: generic type
parameters (to, e.g., use a generic) and archetypes (to map out of a
generic context). Historically, it was also used with
DependentMemberTypes, but recent refactoring to eliminate witness
markers eliminate that code path.
Therefore, narrow TypeSubstitutionMap's keys to SubstitutableType,
which covers archetypes and generic type parameters. NFC
The witnesses in a NormalProtocolConformance have never been
completely serialized, because their substitutions involved a weird
mix of archetypes that blew up the deserialization code. So, only the
witness declarations themselves got serialized. Many clients (the type
checker, SourceKit, etc.) didn't need the extra information, but some
clients (e.g., the SIL optimizers) would end up recomputing this
information. Ick.
Now, serialize the complete Witness structure along with the AST,
including information about the synthetic environment, complete
substitutions, etc. This should obsolete some redundant code paths in
the SIL optimization infrastructure.
This (de-)serialization code takes a new-ish approach to serializing
the synthetic environment in that it avoids serializing any
archetypes. Rather, it maps everything back to interface types during
serialization, and deserialization forms a new generic environment
(with new archetypes!) on-the-fly, mapping deserialized types back
into that environment (and to those archetypes). This way, we don't
have to maintain identity of archetypes in the deserialization code,
and might get some better re-use of the archetypes.
More of rdar://problem/24079818.