-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Debug] Add _DebugDescription macro #69626
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
Conversation
@swift-ci test |
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.
LGTM few nits
@swift-ci test |
@swift-ci test windows |
// 1. The body must have a single item | ||
// 2. The single item must be a string literal | ||
// 3. Later on, the interpolation in the string literal will be validated. | ||
guard let codeBlock = descriptionProperty.accessorBlock?.accessors.as(CodeBlockItemListSyntax.self), |
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.
Hmm, this will be a bit of an issue. A macro applied to a type shouldn't be able to see the bodies of functions defined within that type, because (for example) we need to be able to determine the members and layout of a type without evaluating the bodies of functions. Unfortunately, @hborla and I discussed this and (IIRC) it's described in a proposal, but the compiler fails to enforce it.
I think what we'll end up needing to do here is collect information about the type itself in a member-attribute macro, then use it to add an attribute to the "description" property which can look at the body. I think that can be made to work.
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.
because (for example) we need to be able to determine the members and layout of a type without evaluating the bodies of functions
does this apply to a peer macro? Since a peer macro doesn't introduce any members, the compiler could determine the members and layout independent of expansion of the peer macro.
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 what we'll end up needing to do here is collect information about the type itself in a member-attribute macro, then use it to add an attribute to the "description" property which can look at the body. I think that can be made to work.
I think this makes sense except for one missing piece to the puzzle. The macro attached do description
won't have the ability to emit a (global) constant to a custom section. Not currently. Perhaps a change to the compiler could allow a macro attached to description
to emit data to a custom section. Thoughts?
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.
correction: it is now possible to emit static properties to custom sections, thanks to this recent change: #69192
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.
See e2b3659
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.
Just a few minor style comments
public static func expansion<DeclGroup, DeclSyntax, Context>( | ||
of node: AttributeSyntax, | ||
attachedTo declaration: DeclGroup, | ||
providingAttributesFor member: DeclSyntax, | ||
in context: Context | ||
) | ||
throws -> [AttributeSyntax] | ||
where DeclGroup: DeclGroupSyntax, DeclSyntax: DeclSyntaxProtocol, Context: MacroExpansionContext |
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 be simplified to
public static func expansion<DeclGroup, DeclSyntax, Context>( | |
of node: AttributeSyntax, | |
attachedTo declaration: DeclGroup, | |
providingAttributesFor member: DeclSyntax, | |
in context: Context | |
) | |
throws -> [AttributeSyntax] | |
where DeclGroup: DeclGroupSyntax, DeclSyntax: DeclSyntaxProtocol, Context: MacroExpansionContext | |
public static func expansion( | |
of node: AttributeSyntax, | |
attachedTo declaration: some DeclGroupSyntax, | |
providingAttributesFor member: some DeclSyntaxProtocol, | |
in context: some MacroExpansionContext | |
) | |
throws -> [AttributeSyntax] |
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 will add a comment. The reason it's written this way is because of an lldb bug which doesn't yet support some
style generics. The way it's written allows me to po
swift-syntax values.
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.
In that case, I would prefer to not use DeclSyntax
as a generic type because it shadows the DeclSyntax
type from SwiftSyntax.
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 updated this PR to use the some
syntax, and kept my local working copy with the generic syntax.
let arguments = argumentList.map(\.expression) | ||
guard let typeIdentifier = String(expr: arguments[0]), | ||
let computedProperties = Array<String>(expr: arguments[1]) else { | ||
assertionFailure("_DebugDescriptionProperty called incorrectly") |
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.
In general, I would prefer to emit errors here instead of hitting assertionFailure
s. As I mentioned above, somebody might redeclare _DebugDescriptionPropertyMacro
.
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'm not sure what scenario would result in broken internals being used for real. Also, that these hypothetical errors would not be in the code written by a user.
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’m just thinking that in general it’s nicer to throw errors than to crash because they tend to be more actionable for the user. Either because they re-declared the macro or because there was some hole that we missed. But up to you.
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 took your suggestion. No more asserts, only diagnostics.
@swift-ci test |
@swift-ci test |
Test failures are due to use of |
@swift-ci test |
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.
This is looking great!
|
||
extension MemberAccessExprSyntax { | ||
/// Parse a member access consisting only of property references. Any other syntax throws an error. | ||
fileprivate func propertyChain() throws -> [DeclReferenceExprSyntax] { |
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.
It's somewhat stylistic, but you could consider putting this on ExprSyntaxProtocol
and dealing with both the DeclReferenceExprSyntax
and MemberAccessExprSyntax
cases there. Then the client of this function wouldn't have to separate them out.
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 like it, thanks! Done in e54634c.
@swift-ci test |
1 similar comment
@swift-ci test |
This pull broke building the stdlib with a compiler with
|
Thanks. It seems I should restore the |
Make `_DebugDescription` macro conditional upon macro availability in the build. The `Macros` feature is based on the value of `SWIFT_BUILD_SWIFT_SYNTAX`. See #69626 (comment)
Implementation of the DebugDescription macro pitched on the forums: https://forums.swift.org/t/pitch-debug-description-macro/67711. In this initial commit, the macro is named `_DebugDescription` to indicate it's internal use at this time, pending Swift Evolution. rdar://115180949
) Make `_DebugDescription` macro conditional upon macro availability in the build. The `Macros` feature is based on the value of `SWIFT_BUILD_SWIFT_SYNTAX`. See swiftlang#69626 (comment)
struct MyStruct1: CustomStringConvertible { | ||
var description: String { "thirty" } | ||
} | ||
// CHECK: static let _lldb_summary = ( |
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.
It would be a good idea for the macro to explicitly declare the type of the _lldb_summary
property:
// CHECK: static let _lldb_summary = ( | |
// CHECK: static let _lldb_summary: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) = |
While Swift allows you to infer a property's type from its initial value expression, that can impact compiler performance by forcing the compiler to type-check the initial value expression when it's compiling other files. We're generating these declarations anyway, so we might as well generate an explicit type when we do.
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.
Thanks. This was mentioned on the SE discussion just the other day. I assumed, incorrectly, that the way it was generated would be fine. I did a couple benchmarks with reasonable sized tuples and there was a moderate differences in wall time. Do you have any opinion on whether to introduce a local type alias for the tuple (which was suggested in the SE discussion)? I think benefit would be a slightly more readable macro expansion output, but a tuple of bytes isn't particularly readable in the first place.
Implementation of the DebugDescription macro pitched on the forums: https://forums.swift.org/t/pitch-debug-description-macro/67711. In this initial commit, the macro is named
_DebugDescription
to indicate it's internal use at this time, pending Swift Evolution.rdar://115180949