-
Notifications
You must be signed in to change notification settings - Fork 439
Prepend SyntaxStringInterpolationError
errors in macro expansion with Internal macro error:
#2176
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
Prepend SyntaxStringInterpolationError
errors in macro expansion with Internal macro error:
#2176
Conversation
// Used in `MacroExpansionContext` to make a nicer error message when a | ||
// macro expansion fails with SwiftSyntaxBuilder making a syntax node | ||
// with string interpolation. | ||
@_spi(Diagnostics) public enum SyntaxStringInterpolationError: Error, CustomStringConvertible { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't know if it's okay to @_spi
this, but that seemed like a better option than to make it public outright.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just checked and SyntaxStringInterpolationError
currently serves two distinct use cases:
- The
.diagnostics
case inSyntaxProtocol(validating:)
- The
.producedInvalidNodeType
case in SyntaxNodeWithBody andDeclSyntaxProtocol.init
I think what we should do, is split the error into two distinct structs and make the one that represents the producedInvalidNodeType
case public. That way, we minimize the public surface are we are introducing while also allowing other clients to catch that case.
Tests/SwiftSyntaxMacroExpansionTest/MacroExpansionContextTests.swift
Outdated
Show resolved
Hide resolved
Tests/SwiftSyntaxMacroExpansionTest/MacroExpansionContextTests.swift
Outdated
Show resolved
Hide resolved
// Used in `MacroExpansionContext` to make a nicer error message when a | ||
// macro expansion fails with SwiftSyntaxBuilder making a syntax node | ||
// with string interpolation. | ||
@_spi(Diagnostics) public enum SyntaxStringInterpolationError: Error, CustomStringConvertible { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just checked and SyntaxStringInterpolationError
currently serves two distinct use cases:
- The
.diagnostics
case inSyntaxProtocol(validating:)
- The
.producedInvalidNodeType
case in SyntaxNodeWithBody andDeclSyntaxProtocol.init
I think what we should do, is split the error into two distinct structs and make the one that represents the producedInvalidNodeType
case public. That way, we minimize the public surface are we are introducing while also allowing other clients to catch that case.
let context = BasicMacroExpansionContext() | ||
let error = SyntaxStringInterpolationError.producedInvalidNodeType(expectedType: DeclSyntax.self, actualType: ExprSyntax.self) | ||
// Since we only care about the error switch inside of addDagnostics, we don't care about the particular node we're passing in. | ||
context.addDiagnostics(from: error, node: ExprSyntax("1")) | ||
|
||
XCTAssertEqual(context.diagnostics.count, 1) | ||
XCTAssertTrue(context.diagnostics.first!.message.starts(with: "Internal macro error:")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you should be able to test the real-case scenario when this happens by defining an extension macro that returns
try ExtensionDeclSyntax("var x: Int")
And then use assertMacroExpansion
to check that the emitted error contains Internal macro error:
716ed0f
to
34a634a
Compare
- This commit prepends `SyntaxStringInterpolationError` message with `Internal macro error:` when adding it as a diagnostic in `MacroExpansionContext.addDiagnostics`, so that macro expansion clarifies the error as internal to the macro, not to how it was applied. - Any unrecognized errors raised and sent to `addDiagnostics` will be added as is, without prepending them with a message. That's consistent with how it works now. - Adds a basic test for `addDiagnostics` for that behavior. - Adds end to end test with `assertMacroExpansion`, thanks @ahoppen for the hint!
34a634a
to
0df36e7
Compare
@ahoppen, thank you for the review! I've cleaned up the code and added an end-to-end test for now. The next part is splitting the error enum into two pieces. That'll be a separate commit. |
@ahoppen ready for review! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple of minor comments, otherwise LGTM.
// Start the diagnostic on a new line so it isn't prefixed with the file, which messes up the | ||
// column-aligned message from ``DiagnosticsFormatter``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we keep this comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, added that comment back <3
@@ -12,6 +12,7 @@ | |||
|
|||
import SwiftDiagnostics | |||
import SwiftSyntax | |||
@_spi(Diagnostics) import SwiftSyntaxBuilder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don’t think we need @_spi(Diagnostics)
anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! Sorry I missed it.
} | ||
} | ||
|
||
final class MacroExpansionContextTests: XCTestCase { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a better name for this test would now be something like StringInterpolationErrorTests
.
Oooops, those are embarrassing. I’ll clean it up.
|
21e2acc
to
02517bc
Compare
@ahoppen done! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One minor comment, otherwise LGTM.
// Since we only care about the error switch inside of addDagnostics, we don't care about the particular node we're passing in | ||
context.addDiagnostics(from: error, node: ExprSyntax("1")) | ||
XCTAssertEqual(context.diagnostics.count, 1) | ||
XCTAssertTrue(context.diagnostics.first!.message.starts(with: "Internal macro error:")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you do the following? That way the test doesn’t crash if there is no diagnostic.
XCTAssertTrue(context.diagnostics.first!.message.starts(with: "Internal macro error:")) | |
let diagnostic = try XCTUnwrap(context.diagnostics.first) | |
XCTAssertTrue(diagnostic.message.starts(with: "Internal macro error:")) |
Same for the test below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, good call. Fixed.
This commit splits `SyntaxStringInterpolationError` into two error types: - `SyntaxStringInterpolationInvalidTokenTypeError` for situations when interpolation resulted in a wrong token type, and - `SyntaxStringInterpolationDiagnosticError` when another error occured, and the user provides additional diagnostics with the error. Additionally: - The `SyntaxStringInterpolationInvalidTokenTypeError` is now `public` so other clients can catch it. - Both error types are structs instead of enums. - All invocation spots are updated to match the API.
02517bc
to
ec8265e
Compare
@swift-ci Please test |
@swift-ci please test windows |
1 similar comment
@swift-ci please test windows |
@swift-ci please test Windows |
1 similar comment
@swift-ci please test Windows |
Summary
This pull request prepends
SyntaxStringInterpolationError
message withInternal macro error:
. Closes #2039.Changes
MacroExpansionContext.addDiagnostics
, if the passederror as? SyntaxStringInterpolationError
worked, we prepend it with theInternal macro error
and grab it's description. Otherwise, we just useString(describing:error)
as the diagnostic message.addDiagnostics
for that behavior.Next steps