Skip to content

Overhaul mapTypeIntoContext() #76445

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Sep 14, 2024

Conversation

slavapestov
Copy link
Contributor

@slavapestov slavapestov commented Sep 13, 2024

mapTypeIntoContext() is now implemented as a TypeTransform, instead of via subst().

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 call getNestedType() 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 an ErrorType 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 using subst(), for the same behavior as before.

Also, previously, getNestedType() would end up calling getLocalRequirements() 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 call ArchetypeType::getSuperclass().

At this point, there is not much of a reason to keep the diagnostic that bans a requirement like T: C<T> or T: 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:

protocol P {
  associatedtype A
}

class C<A>: P {}

extension P where Self: C<Self.A> {}

In the case where C does not conform to any protocols in common with Self, the diagnostic is spurious. I'm leaving it in place for now, though.

Fixes rdar://problem/135348472.

'type' and 'missingType' are contextual types in the generic environment
of the witness thunk. We cannot simply map them into the environment of
the conformance, because if the conforming type is a class, the witness
thunk has an extra generic parameter at depth=0, index=0 and all other
generic parameters are shifted down by one depth.
This avoids a bit of indirection when the input is already known to be
a type parameter, and not just a type that contains type parameters.
@slavapestov slavapestov marked this pull request as ready for review September 13, 2024 19:32
We don't really want to support this, at least not yet, but there
are ways to sneak it past the diagnostic that are hard to close.

Fixes rdar://problem/135348472.
@slavapestov
Copy link
Contributor Author

@swift-ci Please smoke test

@slavapestov
Copy link
Contributor Author

@swift-ci Please test source compatibility

@slavapestov slavapestov merged commit f35c90a into swiftlang:main Sep 14, 2024
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant