-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
syntax: enable attributes and cfg on struct fields #38814
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @nrc (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
cc @rust-lang/lang are we happy to add this? Given that we allow |
Hmm, actually this allows all attributes on fields in struct lits. That still seems ok to me, but not as much of a slam dunk as I thought. |
@Ralith the code looks OK to me, it does need a few tests though. |
Re: other attributes: Would it make sense to be more restrictive? Are there any other locations in the language where cfg is permitted but other attributes are not? Beginning work on tests now. |
@nrc I'm in favor of this change. In general, we've been moving to add attributes everywhere unless there's ambiguity/hard to discern meaning (as we saw with expressions). |
Is using cfg on expressions and/or statements stable? It seems like this might cause problems if that isn't available; since that would require duplicating entire functions for each platform combination. In general, though, I'm in favor. I'm slightly concerned we're moving in the direction of C/C++, where libraries like OpenSSL have a large quantity of fields being "optional" and disabled on certain platforms and/or with certain features, which to some extent heightens complexity for users. I believe @sfackler might have some relevant thoughts on this as he manages the bindings for OpenSSL. |
This doesn't really matter for rust-openssl since we never actually create those structs. I definitely agree that conditionally defining public-facing fields is a pain, though doing that for enum variants is fairly common. On the other hand, conditionally defining internal fields can be pretty nice (e.g. https://github.com/brson/error-chain/blob/master/src/lib.rs#L458) |
For illustration, this patch was inspired by the awkwardness of my employing exactly that pattern in my experimental tokio-based window/input system binding, in which I'm trying to provide a uniform interface dispatching over a set of concrete implementations that differs between platforms. Perhaps there's a better way to accomplish this, but this certainly seems to be the most obvious. Notably, this change alone reduces the need for duplicating entire functions (e.g. |
I am in favor of this change. |
@rfcbot fcp merge The proposal here is to allow attributes on struct fields. This is a relatively small extension to the general trend of allowing attributes on statements and so forth. @nrc is proposing that we approve this (with a feature gate, naturally) without an FCP. I'm in favor since an RFC feels like overkill and we have a big enough backlog as it is. What do you think, @rust-lang/lang? |
Team member @nikomatsakis has proposed to merge this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once these reviewers reach consensus, this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
I do not think this makes sense, we should allow all attributes, including cfg (sorry for the confusion in my earlier comments). @Ralith could you add a feature gate to this PR please? |
Added a feature gate |
@@ -659,6 +659,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { | |||
ExprKind::Struct(ref path, ref fields, ref optional_base) => { | |||
visitor.visit_path(path, expression.id); | |||
for field in fields { | |||
walk_list!(visitor, visit_attribute, field.attrs.iter()); |
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 believe field.attrs.iter()
can be just field.attrs
.
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 cannot. ThinVec
does not implement IntoIterator
. &ThinVec
also does not, leaving only this approach.
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.
Oh right -- field.attrs.deref()
should work then, or just leave as is.
@rfcbot concern struct-fields-in-patterns Is the proposed extension intended to cover fields in patterns as well? I cannot tell from skimming the code, and in any case I do not see any test coverage of fields in patterns. By that "fields in patterns" mean the following: struct S { x: i32, y: i32 }
fn main() {
let s = S { x: 10, y: 20 };
match s {
S {
x: 11, // this is a field in a pattern ...
y: the_y // ... and this is a field in a binding pattern
} => println!("the_y: {}", the_y),
S { x: the_x, y: 20 } => println!("the_x: {}", the_x),
S { .. } => {}
}
} (and of course such patterns can also be used with |
@pnkfelix good question! Seems like the answer should be "yes, those ought to be supported too", right? I guess I expect fields to be configurable at all places where fields appear (definition, struct literal, patterns) |
@pnkfelix That was not the intention, but I agree that it makes sense. I'm working on implementing it now. Getting |
.collect(); | ||
ast::ExprKind::Struct(path, fields, base) | ||
} | ||
expr_kind => expr_kind, |
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.
nit: _ => expr_kind,
match pat_kind { | ||
ast::PatKind::Struct(path, fields, etc) => { | ||
let fields = fields.into_iter() | ||
.filter_map(|a| self.configure_struct_pat_field(a)) |
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 believe you could derive HasAttrs
for Spanned<ast::FieldPat>
, remove configure_struct_pat_field
, and gated feature check in this closure.
self.configure(node).map(|node| Spanned { span: span, node: node }) | ||
} | ||
|
||
pub fn configure_pat_kind(&mut self, pat_kind: ast::PatKind) -> ast::PatKind { |
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 this would be easier to use as configure_pat
.
let mut pattern = pattern.unwrap(); | ||
pattern.node = self.configure_pat_kind(pattern.node); | ||
println!("{:#?}", pattern); | ||
fold::noop_fold_pat(P(pattern), 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.
It's more efficient and idiomatic to do the following here:
pattern.map(|mut pattern| {
// ...
pattern
})
(if you did configure_pat
instead of configure_pat_kind
, the .map
would be there)
@@ -679,15 +679,18 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { | |||
} | |||
|
|||
fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> { | |||
let mut pat = pat.unwrap(); | |||
pat.node = self.cfg.configure_pat_kind(pat.node); |
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.
Same here, also would be solved by having configure_pat
.
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.
@Ralith thanks!
Could you add a feature gate test?
Other than that, r=me pending #38814 (comment).
"attributes on struct literal fields are unstable"); | ||
err.emit(); | ||
} | ||
} |
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.
Perhaps we could refactor out this gated feature check (and the one below) into self.visit_struct_field_attrs()
(c.f. self.visit_expr_attrs()
) and then refactor away self.configure_struct_expr_field()
and self.configure_struct_pat_field()
?
.collect(); | ||
pattern.node = ast::PatKind::Struct(path, fields, etc); | ||
} | ||
_ => (), |
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.
nit: _ => {}
is more idiomatic (or if let
)
This PR is blocked on #38814 (comment). |
@rfcbot resolved struct-fields-in-patterns |
@rfcbot reviewed |
@rfcbot reviewed |
@bors r+ |
📌 Commit 7972c19 has been approved by |
⌛ Testing commit 7972c19 with merge 78ccca8... |
💔 Test failed - status-travis |
… On Thu, Jan 12, 2017 at 10:31 AM, bors ***@***.***> wrote:
💔 Test failed - status-travis
<https://travis-ci.org/rust-lang/rust/builds/191366421>
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#38814 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAD95A9rlDn0bPkS9WXIyx2_6agW51Wtks5rRnGbgaJpZM4LaSVF>
.
|
syntax: enable attributes and cfg on struct fields This enables conditional compilation of field initializers in a struct literal, simplifying construction of structs whose fields are themselves conditionally present. For example, the intializer for the constant in the following becomes legal, and has the intuitive effect: ```rust struct Foo { #[cfg(unix)] bar: (), } const FOO: Foo = Foo { #[cfg(unix)] bar: (), }; ``` It's not clear to me whether this calls for the full RFC process, but the implementation was simple enough that I figured I'd begin the conversation with code.
☀️ Test successful - status-appveyor, status-travis |
I couldn't find a tracking issue to stabilise this. How is the procedure for stabilisation? This would be really nice to have! :-) |
Submitted #41681 as a tracking issue for stability. |
This enables conditional compilation of field initializers in a struct literal, simplifying construction of structs whose fields are themselves conditionally present. For example, the intializer for the constant in the following becomes legal, and has the intuitive effect:
It's not clear to me whether this calls for the full RFC process, but the implementation was simple enough that I figured I'd begin the conversation with code.