Overhaul mapTypeIntoContext() #76445
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
mapTypeIntoContext()
is now implemented as aTypeTransform
, instead of viasubst()
.subst()
is based on replacement of generic parameters; if substituting a dependent member type, we substitute the base type first and then look up the member in the result. This meant that mapping a dependent member type into context would instantiate all of its parent archetypes and then recursively callgetNestedType()
on each one. In the new implementation, all of this goes away. We structurally walk the type we're mapping into context, and replace each type parameter with the archetype without materializing unnecessary archetypes.Now,
mapTypeIntoContext()
will deterministically abort if given an invalid type parameter, instead of silently returning anErrorType
as before. This uncovered a few call sites where we were passing in truly invalid type parameters because we were mixing up generic environments. There was one spot where the type parameter might not be valid for a legitimate reason, and I changed it to do the mapping in a more verbose way usingsubst()
, for the same behavior as before.Also, previously,
getNestedType()
would end up callinggetLocalRequirements()
on the generic signature before looking up the type parameter in the generic environment's cache, so mapping a dependent member type into context would always issue generic signature queries. Now, generic environment's cache now contains both reduced and non-reduced type parameters. We make sure to populate both the original key and the reduced key, if they differ, and we always look up the non-reduced key before performing any generic signature queries.Finally, the superclass type of an archetype is itself written in terms of the generic environment's own archetypes; for example, if you have a requirement like
T: C<U>
. When instantiating an archetype, we would eagerly map the superclass type into context. This could result in circular or unbounded recursion. In the circular case we'd end up with an ErrorType in the AST, and no other diagnostic. In the unbounded case, we would crash. Make this lazy, so that an archetype stores the interface type of its superclass, and only maps it into context if you callArchetypeType::getSuperclass()
.At this point, there is not much of a reason to keep the diagnostic that bans a requirement like
T: C<T>
orT: C<T.A>
. The diagnostic check was not fully sound and people found ways around it, and the only case it's needed is when the superclass type contains a member type that depends on a conformance which becomes redundant, eg:In the case where
C
does not conform to any protocols in common withSelf
, the diagnostic is spurious. I'm leaving it in place for now, though.Fixes rdar://problem/135348472.