-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[6.0] Metadata and runtime support for invertible protocol requirements #72709
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
DougGregor
merged 14 commits into
swiftlang:release/6.0
from
DougGregor:dynamic-invertible-protocols-6.0
Apr 2, 2024
Merged
[6.0] Metadata and runtime support for invertible protocol requirements #72709
DougGregor
merged 14 commits into
swiftlang:release/6.0
from
DougGregor:dynamic-invertible-protocols-6.0
Apr 2, 2024
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@swift-ci please test |
@swift-ci please benchmark |
@swift-ci please test |
We need to track suppressible protocols as part of metadata in the ABI. (cherry picked from commit 32a5b4f)
(cherry picked from commit 223645c)
Introduce metadata and runtime support for describing conformances to "suppressible" protocols such as `Copyable`. The metadata changes occur in several different places: * Context descriptors gain a flag bit to indicate when the type itself has suppressed one or more suppressible protocols (e.g., it is `~Copyable`). When the bit is set, the context will have a trailing `SuppressibleProtocolSet`, a 16-bit bitfield that records one bit for each suppressed protocol. Types with no suppressed conformances will leave the bit unset (so the metadata is unchanged), and older runtimes don't look at the bit, so they will ignore the extra data. * Generic context descriptors gain a flag bit to indicate when the type has conditional conformances to suppressible protocols. When set, there will be trailing metadata containing another `SuppressibleProtocolSet` (a subset of the one in the main context descriptor) indicating which suppressible protocols have conditional conformances, followed by the actual lists of generic requirements for each of the conditional conformances. Again, if there are no conditional conformances to suppressible protocols, the bit won't be set. Old runtimes ignore the bit and any trailing metadata. * Generic requirements get a new "kind", which provides an ignored protocol set (another `SuppressibleProtocolSet`) stating which suppressible protocols should *not* be checked for the subject type of the generic requirement. For example, this encodes a requirement like `T: ~Copyable`. These generic requirements can occur anywhere that there is a generic requirement list, e.g., conditional conformances and extended existentials. Older runtimes handle unknown generic requirement kinds by stating that the requirement isn't satisfied. Extend the runtime to perform checking of the suppressible conformances on generic arguments as part of checking generic requirements. This checking follows the defaults of the language, which is that every generic argument must conform to each of the suppressible protocols unless there is an explicit generic requirement that states which suppressible protocols to ignore. Thus, a generic parameter list `<T, Y where T: ~Escapable>` will check that `T` is `Copyable` but not that it is `Escapable`, and check that `U` is both `Copyable` and `Escapable`. To implement this, we collect the ignored protocol sets from these suppressed requirements while processing the generic requirements, then check all of the generic arguments against any conformances not suppressed. Answering the actual question "does `X` conform to `Copyable`?" (for any suppressible protocol) looks at the context descriptor metadata to answer the question, e.g., 1. If there is no "suppressed protocol set", then the type conforms. This covers types that haven't suppressed any conformances, including all types that predate noncopyable generics. 2. If the suppressed protocol set doesn't contain `Copyable`, then the type conforms. 3. If the type is generic and has a conditional conformance to `Copyable`, evaluate the generic requirements for that conditional conformance to answer whether it conforms. The procedure above handles the bits of a `SuppressibleProtocolSet` opaquely, with no mapping down to specific protocols. Therefore, the same implementation will work even with future suppressible protocols, including back deployment. The end result of this is that we can dynamically evaluate conditional conformances to protocols that depend on conformances to suppressible protocols. Implements rdar://123466649. (cherry picked from commit b167eec)
Add more runtime support for checking suppressible protocol requirements: * Parameter packs now check all of the arguments appropriately * Most structural types now implement checking (these are hard to test). (cherry picked from commit 5b02006)
Form a set of suppressed protocols for a function type based on the extended flags (where future compilers can start recording suppressible protocols) and the existing "noescape" bit. Compare that against the "ignored" suppressible protocol requirements, as we do for other types. This involves a behavior change if any client has managed to evade the static checking for noescape function types, but it's unlikely that existing code has done so (and it was unsafe anyway). (cherry picked from commit 11774e5)
(cherry picked from commit af38d88)
…ments (cherry picked from commit cd20dba)
(cherry picked from commit 5746c11)
(cherry picked from commit 3339edb)
Invertible protocols are currently always mangled with `Ri`, followed by a single letter for each invertible protocol (e.g., `c` and `e` for `Copyable` and `Escapable`, respectively), followed by the generic parameter index. However, this requires that we extend the mangling for any future invertible protocols, which mean they won't be backward compatible. Replace this mangling with one that mangles the bit # for the invertible protocol, e.g., `Ri_` (followed by the generic parameter index) is bit 0, which is `Copyable`. `Ri0_` (then generic parameter index) is bit 1, which is `Escapable`. This allows us to round-trip through mangled names for any invertible protocol, without any knowledge of what the invertible protocol is, providing forward compatibility. The same forward compatibility is present in all metadata and the runtime, allowing us to add more invertible protocols in the future without updating any of them, and also allowing backward compatibility. Only the demangling to human-readable strings maps the bit numbers back to their names, and there's a fallback printing with just the bit number when appropriate. Also generalize the mangling a bit to allow for mangling of invertible requirements on associated types, e.g., `S.Sequence: ~Copyable`. This is currently unsupported by the compiler or runtime, but that may change, and it was easy enough to finish off the mangling work for it. (cherry picked from commit 757ebe2)
(cherry picked from commit 408c5c5)
Collapse the representations of "suppressible" and "invertible" protocol sets. Only minor adjustments were required.
We've decided to use the "invertible protocols" terminology throughout the runtime and compiler, so move over to that terminology consistently.
Fixes rdar://125628899
6481e69
to
5e3604b
Compare
@swift-ci please test |
airspeedswift
approved these changes
Apr 2, 2024
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
T: Copyable
at runtime, e.g., for conditional conformances and existentials.T: Copyable
unless it was specifically disabled (e.g., via aT: ~Copyable
constraint). Moreover, this extends the metadata for nominal types and generic requirements in a manner that is backward compatible except for generic types that suppress conformances. We can't think of any way in which this would cause problems, but it's a risk.