Skip to content
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

[Macros] Implement support for function body macros on closures. #79980

Merged
merged 8 commits into from
Mar 21, 2025

Conversation

hborla
Copy link
Member

@hborla hborla commented Mar 13, 2025

This change adds support for function body macros on closure expressions, gated behind the ClosureBodyMacro experimental feature.

This is pitched at https://forums.swift.org/t/pre-pitch-closure-body-macros/78534. The implementation does not match the current pitch for type checking behavior of macro arguments and expansions; I'll make that change in a follow up PR.

@hborla
Copy link
Member Author

hborla commented Mar 13, 2025

swiftlang/swift-syntax#3016

@swift-ci please smoke test

@hborla hborla force-pushed the closure-body-macro branch from 34715fe to 1a93808 Compare March 13, 2025 16:05
@hborla
Copy link
Member Author

hborla commented Mar 13, 2025

swiftlang/swift-syntax#3016

@swift-ci please smoke test

hborla and others added 6 commits March 18, 2025 20:50
… and up to `}`

The macro is not allowed to write explicit type or `in` keyword.
…lkToClosureExprPre`

If closure body is expanded in expression context we need to do
some special handling to make sure that source ranges are not
completely broken.
The closures are type-checked after macros are expanded
which means that macro cannot reference any declarations
from inner or outer closures as its arguments.

For example:

`_: (Int) -> Void = { x in { @macro(x) in ... }() }`

`x` is not going to be type-checked at macro expansion
time and cannot be referenced by `@Macro`.

Let's walk up declaration contexts until we find first
non-closure one. This means that we can support a local
declaration that is defined inside of a closure because
they are separately checked after outer ones are already
processed.
expanding an attached macro.

This fixes a crash in one of the attached macro tests.
@hborla hborla force-pushed the closure-body-macro branch from 1a93808 to ab19ad2 Compare March 20, 2025 04:51
@hborla
Copy link
Member Author

hborla commented Mar 20, 2025

@swift-ci please smoke test

@hborla hborla marked this pull request as ready for review March 20, 2025 05:11
@@ -1568,6 +1581,142 @@ static SourceFile *evaluateAttachedMacro(MacroDecl *macro, Decl *attachedTo,
return macroSourceFile;
}

static SourceFile *evaluateAttachedMacro(MacroDecl *macro,
ClosureExpr *attachedTo,
Copy link
Member Author

Choose a reason for hiding this comment

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

Much of this code is duplicated from the other overload of evaluateAttachedMacro that accepts a Decl *, but it's probably not hard to generalize using ASTNode instead.

@rintaro
Copy link
Member

rintaro commented Mar 20, 2025

Test failures

  Swift(linux-x86_64) :: SourceKit/Macros/diags.swift
  Swift(linux-x86_64) :: SourceKit/Macros/syntactic_expansion.swift

are due to extra outputs were detected, e.g.

unable to find node: keyword(_CompilerSwiftSyntax.Keyword.struct)

This is from findSyntaxNodeInSourceFile because you're checking ClosureSyntax first, then falling back to DeclSyntax. This happened only in Linux/WIndows because macOS uses XPC service which doesn't propagate stdout/stderr output to the host, but Linux/Windows use in-proc source kit.

@hborla
Copy link
Member Author

hborla commented Mar 20, 2025

@rintaro ah, thank you! I think those print statements are problematic, because no matter what I check first, it's expected for the result to be nil in some cases. I wonder if the print statements should be removed?

@hborla
Copy link
Member Author

hborla commented Mar 20, 2025

@swift-ci please smoke test

This code path isn't on an error path, and the print statement causes
unnecessary build output, which also causes test failures.
@hborla hborla force-pushed the closure-body-macro branch from 6e5c924 to e2aed1f Compare March 20, 2025 18:37
@hborla
Copy link
Member Author

hborla commented Mar 20, 2025

@swift-ci please smoke test

a predicate.

The new overload is used during macro expansion to find the nearest
syntax node that is either a `DeclSyntax` or a `ClosureExprSyntax`.
This avoids an issue where calling the overload that accepts a
specific type may find an outer, unrelated declaration or closure.
@hborla
Copy link
Member Author

hborla commented Mar 21, 2025

@swift-ci please smoke test

@hborla
Copy link
Member Author

hborla commented Mar 21, 2025

@swift-ci please smoke test Linux

@hborla
Copy link
Member Author

hborla commented Mar 21, 2025

@swift-ci please test Windows

@hborla hborla merged commit be670da into swiftlang:main Mar 21, 2025
3 checks passed
@hborla hborla deleted the closure-body-macro branch March 21, 2025 13:19
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.

3 participants