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

Invalid attribute specifications being ignored; should cause compile error. #96

Closed
thedodd opened this issue May 30, 2020 · 5 comments · Fixed by #113
Closed

Invalid attribute specifications being ignored; should cause compile error. #96

thedodd opened this issue May 30, 2020 · 5 comments · Fixed by #113

Comments

@thedodd
Copy link

thedodd commented May 30, 2020

Absolutely excellent crate! I have been able to reduce the amount of code needed in one of my projects by a pretty drastic degree (thedodd/wither#48). Thanks for all of the excellent work here @TedDriggs!

One issue that I'm running into right now is that if a user attempts to specify a value for an enum attribute being derived, if the user does not use the syntax expected by darling, it looks like the value is either:

  • skipped and set to a default if #[darling(default)] is specified on the corresponding FDI field.
  • or if no default attr is present, then a Missing field error is generated ... which is going to be deceptive to users because in this case they have specified the field, it is just specified in a way that is apparently unexpected by darling (which my not be intuitive to some).

To use the example which @ubolonton gave in #74 for the type enum Name, if the end user were to attempt to provide the attribute as a type literal, say #[pkg(name = Name::Fn)] or #[pkg(name = Name::Str("val"))], doing so would trigger the behavior I've described above.

The behavior I would expect would be that an error would be generated telling the user that they've specified the value for the attribute incorrectly. Any thoughts on what we should do to fix this issue?

@TedDriggs
Copy link
Owner

I think you'd need to change the generated derivation to handle all syntaxes, and to then produce a "wrong style" error or something.

My hesitation with doing so is that it manual implementation of these cases would be a pain for anyone who wasn't deriving FromMeta. That creates a suboptimal situation where either a) the manual implementer of FromMeta has to write a lot of boilerplate or b) errors are visibly different between derived and manual implementations.

My hope is that darling's results are familiar enough to most Rust devs that they won't encounter these errors often. Are users of your crate struggling with this in specific scenarios/with specific data types? An alternate solution might be to make the derived FromMeta implementations for those types be more forgiving in what they accept.

@jonasbb
Copy link
Contributor

jonasbb commented Dec 30, 2020

I think I am running into the same issue with my serde_with crate, concretely the serde_as field attribute. A user reported this bug: jonasbb/serde_with#233.

I am parsing a field attribute like this. The as part is optional. The intended form is with a string argument containing a type. The as needs a value, that is the "word" form is not possible.

// ...
struct Abc {
    #[serde_as(as = "Vec<_>")]
    field: Vec<u32>,
}

If somebody mistypes the attribute as #[serde_as(as = Vec<_>)] (note the missing quotes) than no error is raised. I also haven't even found a way to manually detect that this is happening except for manually parsing the whole attribute, thus obsoleting the need for darling.

This also interacts badly with the "Unknown field" error.
This #[serde_as(xy = "Vec")] raises the "Unknown field" error, whereas #[serde_as(xy = Vec)] is silently accepted.

@TedDriggs is there any way to raise an error when this happens?

@TedDriggs
Copy link
Owner

I've figured out what's happening here, and have a draft fix for the problem.

In a new minor version, darling will start raising an error when FromDeriveInput, FromTypeParam, FromField, or FromVariant sees an attribute it was told to parse that isn't a valid meta-list. That won't suppress the missing field errors (it's possible to declare the same attribute name multiple times, so a malformed attribute doesn't preclude all other errors), but it will give the user some better information.

Open Questions

  1. Is anyone depending on darling's current 'ignore' behavior? There's no way to test for this, so it may be safest to ship 0.12.0 without an escape hatch and then add one in 0.12.1 if needed.
  2. Should darling error on or ignore #[serde_as] as a standalone attribute? We can understand it as "no additional information"
  3. What should the error message be? The syn one is pretty terse, and part of the darling value proposition is great error messages out of the box.

@jonasbb
Copy link
Contributor

jonasbb commented Jan 4, 2021

2. Should `darling` error on or ignore `#[serde_as]` as a standalone attribute? We can understand it as "no additional information"

If all fields of the struct are specified with #[darling(default)] then parsing should succeed in my opinion.

An empty #[serde_as] on a field is meaningless for my crate. As such it would be nice if I could differentiate between no attribute at all and an attribute, but without any arguments.
Something like #[darling(attributes(serde_as), forward_attrs(serde_as))] would suffice for me though, since then I can check if the attrs vector is empty or not.

3. What should the error message be? The `syn` one is pretty terse, and part of the `darling` value proposition is great error messages out of the box.

Ideally the error message spells out what is what and if possible how to correct this.

For an unknown field #[serde_as(xy = Vec)] I would expect to see the unknown field error, maybe additionally telling how to fix the value part after the =.

error: Unknown field: `xy`
#[serde_as(xy = Vec<_>)]`
           ^^
field: Vec<u32>,

For a known field, but missing quotes #[serde_as(as = Vec<_>)], I would like to see an error pointing to the key-value pair or just the value part and a suggestion how to fix it. Something along those lines:

error: Did you mean `"Vec<_>"`
#[serde_as(as = Vec<_>)]`
                ^^^^^^
field: Vec<u32>,

@TedDriggs
Copy link
Owner

That's a good future enhancement on top of the initial scope; for now, I've just added, "Unable to parse attribute: {syn_error_message}" so that I can get the minor version bump completed.

TedDriggs added a commit that referenced this issue Jan 4, 2021
`darling` pre-dates Rust support for non-meta attributes.
These increase flexibility for Rust code, but mean that not `darling`
does not parse all valid attributes.

`darling` previously ignored these outright, creating misleading errors.
This commit makes those explicit errors.

Fixes #96
TedDriggs added a commit that referenced this issue Jan 5, 2021
`darling` pre-dates Rust support for non-meta attributes.
These increase flexibility for Rust code, but mean that not `darling`
does not parse all valid attributes.

`darling` previously ignored these outright, creating misleading errors,
such as claiming all fields were missing. This commit makes unsupported
attributes explicit errors.

To allow for detailed diagnostic information in the future without
changing the crate's public API, the parsing of `Attribute` into
`MetaList` is handled in a new function that wraps `syn`'s own
`parse_meta`. This commit uses that structure to include an attribute
path in an example for the name-value error case; future commits could
expand that function to identify places where the caller may have
missed quotation marks, for example.

Fixes #96
TedDriggs added a commit that referenced this issue Jan 5, 2021
`darling` pre-dates Rust support for non-meta attributes.
These increase flexibility for Rust code, but mean that not `darling`
does not parse all valid attributes.

`darling` previously ignored these outright, creating misleading errors,
such as claiming all fields were missing. This commit makes unsupported
attributes explicit errors.

To allow for detailed diagnostic information in the future without
changing the crate's public API, the parsing of `Attribute` into
`MetaList` is handled in a new function that wraps `syn`'s own
`parse_meta`. This commit uses that structure to include an attribute
path in an example for the name-value error case; future commits could
expand that function to identify places where the caller may have
missed quotation marks, for example.

Fixes #96
TedDriggs added a commit that referenced this issue Jan 5, 2021
`darling` pre-dates Rust support for non-meta attributes.
These increase flexibility for Rust code, but mean that not `darling`
does not parse all valid attributes.

`darling` previously ignored these outright, creating misleading errors,
such as claiming all fields were missing. This commit makes unsupported
attributes explicit errors.

To allow for detailed diagnostic information in the future without
changing the crate's public API, the parsing of `Attribute` into
`MetaList` is handled in a new function that wraps `syn`'s own
`parse_meta`. This commit uses that structure to include an attribute
path in an example for the name-value error case; future commits could
expand that function to identify places where the caller may have
missed quotation marks, for example.

Fixes #96
TedDriggs added a commit that referenced this issue Jan 5, 2021
`darling` pre-dates Rust support for non-meta attributes.
These increase flexibility for Rust code, but mean that not `darling`
does not parse all valid attributes.

`darling` previously ignored these outright, creating misleading errors,
such as claiming all fields were missing. This commit makes unsupported
attributes explicit errors.

To allow for detailed diagnostic information in the future without
changing the crate's public API, the parsing of `Attribute` into
`MetaList` is handled in a new function that wraps `syn`'s own
`parse_meta`. This commit uses that structure to include an attribute
path in an example for the name-value error case; future commits could
expand that function to identify places where the caller may have
missed quotation marks, for example.

Fixes #96
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants