Skip to content

SILGen: Always match noncopyable values by borrowing. #71025

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 1 commit into from
Jan 22, 2024

Conversation

jckarter
Copy link
Contributor

Even if the final pattern ends up consuming the value, the match itself must be nondestructive, because any match condition could fail and cause us to have to go back to the original aggregate. For copyable values, we can always copy our way out of consuming operations, but we don't have that luxury for noncopyable types, so the entire match operation has to be done as a borrow.

For address-only enums, this requires codifying part of our tag layout algorithm in SIL, namely that an address-only enum will never use spare bits or other overlapping storage for the enum tag. This allows us to assume that unchecked_take_enum_data_addr is safely non-side- effecting and match an address-only noncopyable enum as a borrow. I put TODOs to remove defensive copies from various parts of our copyable enum codegen, as well as to have the instruction report its memory behavior as None when the projection is nondestructive, but this disturbs SILGen for existing code in ways SIL passes aren't yet ready for, so I'll leave those as is for now.

This patch is enough to get simple examples of noncopyable enum switches to SILGen correctly. Additional work is necessary to stage in the binding step of the pattern match; for a consuming switch, we'll need to end the borrow(s) and then reproject the matched components so we can consume them moving them into the owned bindings. The move-only checker also needs to be updated because it currently always tries to convert a switch into a consuming operation.

Even if the final pattern ends up consuming the value, the match itself
must be nondestructive, because any match condition could fail and cause
us to have to go back to the original aggregate. For copyable values,
we can always copy our way out of consuming operations, but we don't
have that luxury for noncopyable types, so the entire match operation
has to be done as a borrow.

For address-only enums, this requires codifying part of our tag layout
algorithm in SIL, namely that an address-only enum will never use
spare bits or other overlapping storage for the enum tag. This allows
us to assume that `unchecked_take_enum_data_addr` is safely non-side-
effecting and match an address-only noncopyable enum as a borrow.
I put TODOs to remove defensive copies from various parts of our
copyable enum codegen, as well as to have the instruction report
its memory behavior as `None` when the projection is nondestructive,
but this disturbs SILGen for existing code in ways SIL passes aren't
yet ready for, so I'll leave those as is for now.

This patch is enough to get simple examples of noncopyable enum switches
to SILGen correctly. Additional work is necessary to stage in the binding
step of the pattern match; for a consuming switch, we'll need to end
the borrow(s) and then reproject the matched components so we can
consume them moving them into the owned bindings. The move-only checker
also needs to be updated because it currently always tries to convert
a switch into a consuming operation.
@jckarter
Copy link
Contributor Author

@swift-ci Please test

@jckarter jckarter merged commit 47ee847 into swiftlang:main Jan 22, 2024
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