Skip to content

SwiftIfConfig improvements to suit usage in the compiler #2819

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 5 commits into from
Aug 24, 2024

Conversation

DougGregor
Copy link
Member

A couple more semantic tweaks and improvements to address the needs of the compiler:

  • Rework the configured regions computation to better match the compiler with respect to inactive vs. unparsed
  • Turn "configured regions" into a proper struct that also carries with it diagnostics and an isActive operation
  • Reimplement SyntaxProtocol.isActive(in:) in terms of configured regions, and warn that it's slow
  • Provide TokenSyntax nodes for the import path in BuildConfiguration.canImport because the compiler really needs location information

The compiler's heuristics for inactive vs. unparsed regions differ from
the implementation in SwiftIfConfig and have changed fairly recently.
Rework the implementation here to match what the compiler does.
Move the "isActive" check for configured regions into this new struct,
and also capture all of the diagnostics.
…ons.

The compiler's semantics for determining unparsed vs. inactive regions
require looking all the way up the `#if` tree to the root, and the
bottom-up implementation of `isActive(in:)` was failing to match the
semantics of configured regions. Use `ConfiguredRegions` directly, with
a note that the performance of `SyntaxProtocol.isActive(in:)` is not
good.

I'm still considering whether this API should go away entirely.
…anImport()

The compiler produces diagnostics for `canImport` checks, which requires
more source location information than was previously provided via
`BuildConfiguration.canImport`. Add in TokenSyntax nodes for each of
the elements in the import path so that the compiler has the syntax node
information it needs.
@DougGregor
Copy link
Member Author

swiftlang/swift#76074

@swift-ci please test

Add a debugDescription so it's easier to see what the regions are, and allow
us to test for exact results.

Tweak the set of configured regions more precisely so they match what the
compiler is expecting. The only difference here is that we create a separate
region for an active block within another active block.
@DougGregor
Copy link
Member Author

swiftlang/swift#76074

@swift-ci please test

@DougGregor
Copy link
Member Author

swiftlang/swift#76074

@swift-ci please test Windows

@DougGregor DougGregor merged commit cdff432 into swiftlang:main Aug 24, 2024
3 checks passed
@DougGregor DougGregor deleted the ifconfig-compiler-improvements branch August 24, 2024 19:39
Comment on lines -125 to +126
func canImport(importPath: [String], version: CanImportVersion) throws -> Bool
func canImport(importPath: [(TokenSyntax, String)], version: CanImportVersion) throws -> Bool
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need both the token and the string? Couldn’t we extract the identifier from the token?

Copy link
Member Author

Choose a reason for hiding this comment

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

The identifier on the token is optional, so we'd be asking clients to either force the optional every time, or add a spurious "guard". I'd rather just duplicate the information.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, I see. Makes sense. I think that explanation in a doc comment would be useful.

Comment on lines +174 to +175
let (foldedCondition, foldDiagnostics) = IfConfigClauseSyntax.foldOperators(condition)
diagnostics.append(contentsOf: foldDiagnostics)
Copy link
Member

Choose a reason for hiding this comment

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

This is now duplicating logic from IfConfigDeclSyntax.activeClause(in:), right? Do you think there’s any way to avoid the duplication? I’m a little worried that they will get out of sync eventually.

Copy link
Member Author

Choose a reason for hiding this comment

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

We can do a little bit better here, because there were 4 copies of code like this.

} else {
// This is an #else. It's active if we haven't found an active clause
// yet and are in an active region.
isActive = !foundActive && inActiveRegion
Copy link
Member

Choose a reason for hiding this comment

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

Do we still need to determine syntaxErrorsAllowed in that case. Eg. assuming that DEBUG is set, do we report print debugDescription as syntaxErrorsAllowed for the following

#if DEBUG
print(debugDescription)
#elseif compiler(>99.0)
print debugDescription
#endif

Copy link
Member Author

Choose a reason for hiding this comment

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

The compiler doesn't determine syntaxErrorsAllowed here, and prints an error for print debugDescription. We could choose to deviate from the compiler here (and be more lax) if we want to.

Copy link
Member

Choose a reason for hiding this comment

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

OK, that’s surprising to me but matching the compiler here for now makes sense for now to make switching between the two implementations easier.

Should we gather these oddities that we find somewhere so we can consider fixing them in the future?

Copy link
Member Author

Choose a reason for hiding this comment

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

It turns out that this behavior changed in the compiler very recently (swiftlang/swift#74415). We could consider whether we need to fix the original issue in some other way.

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