Skip to content

Fix and generalize the printing of suppressible features #41399

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 2 commits into from
Feb 17, 2022

Conversation

rjmccall
Copy link
Contributor

Fix and generalize the printing of suppressible features, and make @_unsafeInheritExecutor a suppressible feature.

Some language features are required in order to parse a declaration correctly, but some can safely be ignored. For the latter, we'd like the module interface to simply contain the declaration twice, once with the feature and once without. Some basic support for that was already added for the SpecializeAttributeWithAvailability feature, but it didn't interact correctly with required features that might be checked in the same #if clause (it simply introduced an #else), and it wasn't really set up to allow multiple features to be handled this way. There were also a few other places that weren't updated to handle this, presumably because they never coincided with a @_specialize attribute.

Introduce the concept of a suppressible feature, which is anything that the ASTPrinter can modify the current PrintOptions in order to suppress. Restructure the printing of compatibility checks so that we can print the body multiple times with different settings. Print required feature checks in an outer #if...#endif, then perform a separate #if...#else...#endif within if we have suppressible features. If there are multiple suppressible features, check for the most recent first, on the assumption that it will imply the rest; then perform subsequent checks with an #elsif clause.

This should be a far more solid foundation on which to build compatibility checks in the future.

@_unsafeInheritExecutor needs to be suppressible because it's been added to some rather important existing APIs. Simply suppressing the entire decl will effectively block old tools from using a new SDK to build many existing projects (if they've adopted async). Dropping the attribute changes the semantics of these functions, but only if the compiler features the SE-0338 scheduling change; this is a very narrow window of main-branch development builds of the tools, none of which were officially released.

@rjmccall
Copy link
Contributor Author

@swift-ci Please test

@rjmccall rjmccall requested a review from DougGregor February 16, 2022 07:47
Copy link
Member

@DougGregor DougGregor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

I wanted a bit vector that I could use as a compact sorted
set of enum values: an inline-allocated, fixed-size array
of bits supporting efficient and convenient set operations
and iteration.

The C++ standard library offers std::bitset, but the API
is far from ideal for this purpose.  It's positioned as
an abstract bit-vector rather than as a set.  To use it
as a set, you have to turn your values into indices, which
for enums means explicitly casting them all in the caller.
There's also no iteration operation, so to find the
elements of the set, you have to iterate over all possible
indices, test whether they're in the set, and (if so)
cast the current index back to the enum.  Not only is that
much more awkward than normal iteration, but it's also
substantially less efficient than what you can get by
counting trailing zeroes in a mask.

LLVM and Swift offer a number of other bit vectors, but
they're all dynamically allocated because they're meant
to track arbitrary sets.  That's not a non-starter for my
use case, which is in textual serialization and so rather
slow anyway, but it's also not very hard to whip together
the optimal data structure here.

I have committed the cardinal sin of C++ data structure
design and provided the operations as ordinary methods
instead of operators.
and make `@_unsafeInheritExecutor` a suppressible feature.

Some language features are required in order to parse a
declaration correctly, but some can safely be ignored.
For the latter, we'd like the module interface to simply
contain the declaration twice, once with the feature and
once without.  Some basic support for that was already
added for the SpecializeAttributeWithAvailability feature,
but it didn't interact correctly with required features
that might be checked in the same `#if` clause (it simply
introduced an `#else`), and it wasn't really set up to
allow multiple features to be handled this way.  There
were also a few other places that weren't updated to
handle this, presumably because they never coincided
with a `@_specialize` attribute.

Introduce the concept of a suppressible feature, which
is anything that the ASTPrinter can modify the current
PrintOptions in order to suppress.  Restructure the
printing of compatibility checks so that we can print
the body multiple times with different settings.
Print required feature checks in an outer `#if...#endif`,
then perform a separate `#if...#else...#endif` within
if we have suppressible features.  If there are multiple
suppressible features, check for the most recent first,
on the assumption that it will imply the rest; then
perform subsequent checks with an `#elsif` clause.

This should be a far more solid foundation on which to
build compatibility checks in the future.

`@_unsafeInheritExecutor` needs to be suppressible
because it's been added to some rather important
existing APIs.  Simply suppressing the entire decl will
effectively block old tools from using a new SDK to
build many existing projects (if they've adopted
`async`).  Dropping the attribute changes the semantics
of these functions, but only if the compiler features
the SE-0338 scheduling change; this is a very narrow
window of main-branch development builds of the tools,
none of which were officially released.
@rjmccall rjmccall force-pushed the suppressible-compatibility-checks branch from c9f1e00 to 54c38cb Compare February 16, 2022 22:58
@rjmccall
Copy link
Contributor Author

@swift-ci Please test

@rjmccall rjmccall merged commit bfffae2 into swiftlang:main Feb 17, 2022
@rjmccall rjmccall deleted the suppressible-compatibility-checks branch February 17, 2022 08:26
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.

2 participants