-
Couldn't load subscription status.
- Fork 4
Emit code + errors on duplicate struct attributes #63
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
Emit code + errors on duplicate struct attributes #63
Conversation
…onfidently write an impl + the error. Similar to how the current macro emits an impl + errors when the `leaf` attribute is used on an enum (as it can have no effect on the generated code). ## Background I identified two other possible locations for this behavior in https://schneems.com/2025/03/26/a-daft-procmacro-trick-how-to-emit-partialcode-errors/. This PR addresses one of them: duplicate attributes on a struct. Related conversation https://ruby.social/@Schneems/114230457184998727
| } else { | ||
| for error in duplicates { | ||
| errors.push(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.
The idea is to bypass errors.has_errors() check so we return Some here. It's only nested one level deep so that's enough to get it to produce code:
fn make_struct_impl(
input: &DeriveInput,
s: &DataStruct,
errors: ErrorSink<'_, syn::Error>,
) -> Option<TokenStream> {
let Some(struct_config) =
StructConfig::parse_from(&input.attrs, errors.new_child())
else {
// An error occurred parsing the struct configuration -- don't generate
// anything.
return None;
};Though this initial commit fails to add the duplicates back in in the event of a larger 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.
Though this initial commit fails to add the duplicates back in in the event of a larger error.
Fixed in the second commit and I added a test exercising this mixed-error case.
The field code is nested much deeper than the struct error code making it non-trivial to apply there. One possible option is introducing some differentiation between the types of errors that are held by ErrorSink such as "critical_error" versus "warn_error." So we could have if errors.has_critical_error() { instead of if errors.has_errors() {
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! I see what you mean, and I really like the idea of having two categories of errors the way you've described them. How about updating ErrorSink to have "errors" and "warnings", knowing that we have to produce errors for warnings due to proc-macro API limitations.
edfee73 to
bcf735e
Compare
|
@schneems Just a fly by to say that I really enjoyed and appreciated your blog post! |
|
@sunshowers I implemented the suggestion to split up warnings and critical errors in #64 and I like how it turned out. The actual "emit code + errors" change once the infrastructure is in place was a one line edit which felt great. I'll close this one. Also (might interest you) I have a PR open to syn to add docs to some of the lesser-known capabilities of syn::Error dtolnay/syn#1855. I'm open to feedback there or on mastodon for suggestions on how to improve the PR if you've got any.
Thanks for saying so @andrewjstone! I got very little feedback on it (no comments where it was posted), thanks for taking the time to let me know. |
Removing duplicate attributes won't change the code emitted, we can confidently write an impl + the error. Similar to how the current macro emits an impl + errors when the
leafattribute is used on an enum (as it can have no effect on the generated code).Background
I identified two other possible locations for this behavior in https://schneems.com/2025/03/26/a-daft-procmacro-trick-how-to-emit-partialcode-errors/. This PR addresses one of them: duplicate attributes on a struct.
Related conversation https://ruby.social/@Schneems/114230457184998727