Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upExpand items before their derives #48465
Conversation
rust-highfive
assigned
nikomatsakis
Feb 23, 2018
This comment has been minimized.
This comment has been minimized.
|
(rust_highfive has picked a reviewer for you, use r? to override) |
rust-highfive
added
the
S-waiting-on-review
label
Feb 23, 2018
This comment has been minimized.
This comment has been minimized.
|
r? @nrc cc @keeperofdakeys @dtolnay @sgrif @alexcrichton @jseyfried (users participating on original PR) |
rust-highfive
assigned
nrc
and unassigned
nikomatsakis
Feb 23, 2018
abonander
changed the title
[WIP] expand items before their derives
Expand items before their derives
Feb 24, 2018
This comment has been minimized.
This comment has been minimized.
|
@nrc Build passed, will squash after review |
This comment has been minimized.
This comment has been minimized.
|
cc #38356 |
This comment has been minimized.
This comment has been minimized.
|
|
bors
added
S-waiting-on-author
and removed
S-waiting-on-review
labels
Feb 27, 2018
abonander
force-pushed the
abonander:expansion_order
branch
from
31c2fae
to
bf39cb5
Feb 27, 2018
This comment has been minimized.
This comment has been minimized.
|
@petrochenkov perhaps you'd like to look at this one too? |
petrochenkov
self-assigned this
Feb 27, 2018
petrochenkov
added
S-waiting-on-review
and removed
S-waiting-on-author
labels
Feb 27, 2018
This comment has been minimized.
This comment has been minimized.
|
Started reviewing, will finish tomorrow. |
This comment has been minimized.
This comment has been minimized.
|
|
bors
added
S-waiting-on-author
and removed
S-waiting-on-review
labels
Mar 3, 2018
petrochenkov
added
S-waiting-on-review
and removed
S-waiting-on-author
labels
Mar 3, 2018
abonander
force-pushed the
abonander:expansion_order
branch
from
228c8cb
to
f33551c
Mar 4, 2018
petrochenkov
reviewed
Mar 4, 2018
| let item = item.map_attrs(|mut attrs| { | ||
| attrs.retain(|a| a.path != "structural_match" && a.path != "rustc_copy_clone_marker"); | ||
| attrs | ||
| }); |
This comment has been minimized.
This comment has been minimized.
petrochenkov
Mar 4, 2018
•
Contributor
@abonander
Do you know why these attributes are filtered away here?
They are normally produced by builtin derives, but I'm not sure how they affect custom derives and why they need to be filtered away before applying a custom derive.
This comment has been minimized.
This comment has been minimized.
abonander
Mar 4, 2018
Author
Contributor
@jseyfried added this in the original PR. Naive guess, it's avoiding exposing implementation details to the custom derive? Because these would be retained in the actual item since custom derives don't re-emit the item they're applied to.
This comment has been minimized.
This comment has been minimized.
petrochenkov
Mar 4, 2018
Contributor
custom derives don't re-emit the item they're applied to
Aha, this must be the key observation. Everything looks reasonable then.
petrochenkov
reviewed
Mar 4, 2018
| fn collect_invocations(&mut self, expansion: Expansion, derives: &[Mark]) | ||
| -> (Expansion, Vec<Invocation>) { | ||
| let result = { | ||
| fn collect_invocations(&mut self, |
This comment has been minimized.
This comment has been minimized.
petrochenkov
Mar 4, 2018
Contributor
@abonander
Did you figure out what happens here and above in fn expand?
I can't understand it just by reading the code, but it usually becomes more clear after actively doing some refactoring or modifications.
This comment has been minimized.
This comment has been minimized.
abonander
Mar 4, 2018
Author
Contributor
I'm not sure what you mean by "figure out what happens here". It seems to do what it says on the tin; it accumulates bang/attribute macro invocations and then expand expands them. It has to be done in a loop because macro expansions can produce more invocations.
petrochenkov
reviewed
Mar 4, 2018
| monotonic: bool, // c.f. `cx.monotonic_expander()` | ||
| } | ||
|
|
||
| /* |
This comment has been minimized.
This comment has been minimized.
petrochenkov
reviewed
Mar 4, 2018
| struct Visitor<'a> { | ||
| struct Visitor<'a, 'b: 'a> { | ||
| cx: &'a ExtCtxt<'b>, | ||
| span: Span, |
This comment has been minimized.
This comment has been minimized.
petrochenkov
Mar 4, 2018
Contributor
The original PR removed these fields and fn visit_mac below.
Are they needed again for some reason?
petrochenkov
reviewed
Mar 4, 2018
| for &(derive, _) in derives { | ||
| unresolved.insert(derive); | ||
| self.invocations.insert(derive, invocation); | ||
| } |
This comment has been minimized.
This comment has been minimized.
petrochenkov
Mar 4, 2018
Contributor
Hmm, this commit also reverts some changes done in the original PR.
This comment has been minimized.
This comment has been minimized.
abonander
Mar 4, 2018
Author
Contributor
This and the other nonsensical changes are probably due to a naive rebase where I just applied all nonconflicting changes from both sides. I'll have to go through and fix these or redo the rebase.
This comment has been minimized.
This comment has been minimized.
|
Ok, r=me once Travis is green and all the rebase issues are cleaned up (ideally by doing a "less naive" rebase). EDIT: Also squashing non-@jseyfried commits would be nice. |
This comment has been minimized.
This comment has been minimized.
|
@petrochenkov Since I don't completely understand everything that this code is doing, I'm slightly concerned about derives that declare custom attributes: it seems that this should break it since we would always end up looking at the attributes first and throw an error since they don't resolve to anything. However, the following tests using custom attributes are passing:
Do you think these are enough of a smoke test that we don't need a separate test to ensure this hasn't broken custom attributes for derives? @jseyfried could you weigh in on this since it's mostly your code? |
This comment has been minimized.
This comment has been minimized.
|
Just to give an update, crater run will start in ~4 days. Sorry :( This PR got pushed down because a more time-critical one cropped up. |
This comment has been minimized.
This comment has been minimized.
I'm not sure what is this about exactly. |
This comment has been minimized.
This comment has been minimized.
I thought attributes declared by derives are meant to be applied by the user and consumed by the derive, i.e. removed after the derive completes. This is how Serde uses them anyway: https://serde.rs/attributes.html This PR, at least nominally, expands derives last on an item, processing other macros first: https://github.com/rust-lang/rust/pull/48465/files#diff-54079e90040377e52f969c857e3f558aR21 If we expand the item itself first before its derives, the expander would look at these custom attributes and find that they don't resolve to anything and throw an error. However, the tests I linked are passing which suggests this has already been accounted for. |
This comment has been minimized.
This comment has been minimized.
|
I suspect that the expander classifies the attributes first (into builtin, unknown, whitelisted, macro-attributes of various kinds of legacy-ness) and expands only those that are actually macros. |
This comment has been minimized.
This comment has been minimized.
|
The IIRC this works because errors regarding macro resolution only become a hard error once everything has expanded. This change doesn't make derives happen last, it makes bang macros happen first (so called partial expansions). |
This comment has been minimized.
This comment has been minimized.
|
Mmm, good assessment. I've only recently started getting back into macro expansion stuff so a lot of these changes went over my head. |
This comment has been minimized.
This comment has been minimized.
|
Crater run started |
This comment has been minimized.
This comment has been minimized.
|
This came up again today when discussing procedural macros (e.g., Macros 1.2). I'm still pretty hesitant to make changes here -- it's not clear that expanding before derive is what we want to do. |
This comment has been minimized.
This comment has been minimized.
|
(Re)reviewed, LGTM. Were there any other questions about the code not answered by #48465 (comment) or #48465 (comment)? (thanks @keeperofdakeys!) |
This comment has been minimized.
This comment has been minimized.
|
@nikomatsakis Has @nrc changed his mind? The main motivation for this was that we already "expand" |
This comment has been minimized.
This comment has been minimized.
Yes. Sorry, I did not at all understand what is going on here. I don't think we can land this because changing expansion order is a breaking change, but also because the more complex the expansion order, the harder it is to understand what is going on. The fact that The trouble I think is that one can create examples which benefit from either expansion order. Given that, I think we must go for the most predictable and consistent behaviour, which I believe is the current behaviour. Apologies that I didn't get to this conclusion earlier. |
This comment has been minimized.
This comment has been minimized.
|
@nrc What about making the expansion order opt-in? We could apply some derives pre-expansion and some derives post-expansion. |
This comment has been minimized.
This comment has been minimized.
|
@nrc Ok. To be clear,
I doubt this is breaking in practice, but yeah back-compat could complicate things...
I think it's worth noting though that just about every major derive macro today needs
Can you think of examples of derives that don't want their input fully expanded? These seem like a far smaller class, especially if we assume that attribute macros will eventually be allowed on struct fields.
I think most predictable/consistent would be either everything is expanded first, or the macro sees the original, raw, unmodified I like @abonander's idea of allowing the macro author to request either unexpanded or fully expanded input. If derive back-compat is an issue, not requesting either could default to today's behavior. |
This comment has been minimized.
This comment has been minimized.
|
Something like
Or do we want to provide it as a general mechanism in |
This comment has been minimized.
This comment has been minimized.
|
Just providing |
This comment has been minimized.
This comment has been minimized.
|
I meant for that to be the way to opt-in to input expansion, by programmatically asking for it: #[proc_macro_derive(MyTrait)]
pub fn my_trait_derive(input: TokenStream) -> TokenStream {
let expanded = proc_macro::expand(input);
// ...
} |
This comment has been minimized.
This comment has been minimized.
So, for proper proc macros my preferred way to opt-in is to let macros eagerly expand macros in their body by adding
Where |
This comment has been minimized.
This comment has been minimized.
|
Ok,
Interesting, ideally I would have hoped "inert attributes" would be used for that: |
This comment has been minimized.
This comment has been minimized.
Hmm, this is an excellent question. I'm not really sure - I don't see why from a design perspective, however, from an implementation point of view messing with the order of 'expansion' of cfgs c.f. macros might be hard.
iiuc, the problem there is that writing a lot of code inside an attribute is not so nice to look at. |
This comment has been minimized.
This comment has been minimized.
Nah, it'd be pretty straightforward -- quite a bit simpler than this PR.
Yeah... I think with the right formatting it'd still be nicer, but if that's what's being done in the wild then so be it. |
This comment has been minimized.
This comment has been minimized.
|
Hi @petrochenkov (crater requester/PR reviewer)! Crater results are at: http://cargobomb-reports.s3.amazonaws.com/pr-48465/index.html. 'Blacklisted' crates (spurious failures etc) can be found here. If you see any spurious failures not on the list, please make a PR against that file. (interested observers: Crater is a tool for testing the impact of changes on the crates.io ecosystem. You can find out more at the repo if you're curious) |
This comment has been minimized.
This comment has been minimized.
|
We've got some significant breakages in derive crates:
Several of these derives were expecting |
petrochenkov
added
S-waiting-on-author
and removed
S-waiting-on-crater
labels
Apr 1, 2018
This comment has been minimized.
This comment has been minimized.
|
@abonander |
This comment has been minimized.
This comment has been minimized.
|
Thing with RFCs is that they're primarily for proposing solutions and I don't think we've gotten that far. I think exposing input expansion programmatically (in |
This comment has been minimized.
This comment has been minimized.
Yeah, a pre-RFC on IRLO would probably be even better. |
petrochenkov
closed this
Apr 1, 2018
This comment has been minimized.
This comment has been minimized.
|
Created a topic on IRLO: https://internals.rust-lang.org/t/pre-rfc-input-expansion-for-proc-macros-derives-primarily/7210 |
abonander commentedFeb 23, 2018
•
edited
continuation of #41029
closes #47358