-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
RFC for attributes on statements and blocks. #16
Changes from 1 commit
fed1f9f
7520d05
6148795
403d222
a037604
0130066
12e924b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
`if` is annoying.
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ | |
# Summary | ||
|
||
Allow attributes on more places inside functions, such as statements, | ||
blocks and (possibly) expressions. | ||
blocks and expressions. | ||
|
||
# Motivation | ||
|
||
|
@@ -45,7 +45,7 @@ for relatively precise attribute handling. | |
|
||
# Detailed design | ||
|
||
Normal attribute syntax on `let` statements and blocks. | ||
Normal attribute syntax on `let` statements, blocks and expressions. | ||
|
||
```rust | ||
fn foo() { | ||
|
@@ -61,55 +61,110 @@ fn foo() { | |
unsafe { | ||
// code | ||
} | ||
#[attr4] foo(); | ||
|
||
#[attr5] | ||
if cond { | ||
bar() | ||
} else #[attr6] if cond { | ||
baz() | ||
} else #[attr7] { | ||
|
||
}; | ||
|
||
let x = #[attr8] 1; | ||
|
||
qux(3 + #[attr9] 2); | ||
|
||
foo(x, #[attr10] y, z); | ||
} | ||
``` | ||
|
||
## Extension to arbitrary expressions | ||
## `cfg` | ||
|
||
It would also be theoretically possible to extend this to support | ||
arbitrary expressions (rather than just blocks, which are themselves | ||
expressions). This would allow writing | ||
It is an error to place a `#[cfg]` attribute on a non-statement | ||
expressions, including `if`s/blocks inside an `if`/`else` chain, that | ||
is, `attr1`--`attr7` can legally be `#[cfg(foo)]`, but | ||
`attr8`--`attr10` cannot, since it makes little sense to strip code | ||
down to `let x = ;`. | ||
|
||
Attributes bind tighter than any operator, that is `#[attr] x op y` is | ||
always parsed as `(#[attr] x) op y`. | ||
|
||
## Inner attributes | ||
|
||
Inner attributes can be placed at the top of blocks (and other | ||
structure incorporating a block) and apply to that block. | ||
|
||
```rust | ||
fn foo() { | ||
#[attr4] foo(); | ||
{ | ||
#![attr11] | ||
|
||
#[attr5] if cond { | ||
bar() | ||
} else #[attr6] { | ||
baz() | ||
} | ||
foo() | ||
} | ||
|
||
let x = #[attr7] 1; | ||
match bar { | ||
#![attr12] | ||
|
||
qux(3 + #[attr8] 2); | ||
_ => {} | ||
} | ||
|
||
foo(x, #[attr9] y, z); | ||
if cond { | ||
#![attr13] | ||
} | ||
|
||
// are the same as | ||
|
||
#[attr11] | ||
{ | ||
foo() | ||
} | ||
|
||
#[attr12] | ||
match bar { | ||
_ => {} | ||
} | ||
``` | ||
|
||
These last examples indicate a possible difficulty: what happens with | ||
say `1 + #[cfg(foo)] 2`? This should be an error, i.e. `#[cfg]` is | ||
only allowed on the "exterior" of expressions, that is, legal in all | ||
examples above except `#[attr7]` and `#[attr8]`. `#[attr9]` is | ||
questionable: if it were a `cfg`, then it could reasonably be | ||
interpreted as meaning `foo(x, z)` or `foo(x, y, z)` conditional on | ||
the `cfg`. | ||
#[attr13] | ||
if cond { | ||
} | ||
``` | ||
|
||
Allowing attributes there would also require considering | ||
precedence. There are two sensible options, `#[...]` binds tighter | ||
than everything else, i.e. `#[attr] 1 + 2` is `(#[attr] 1) + 2`, or it | ||
is weaker, so `#[attr] 1 + 2` is `#[attr] (1 + 2)`. | ||
|
||
# Alternatives | ||
|
||
These instances could possibly be approximated with macros and helper | ||
functions, but to a low degree degree (e.g. how would one annotate a | ||
general `unsafe` block). | ||
|
||
Only allowing attributes on "statement expressions" that is, | ||
expressions at the top level of a block, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @huonw oops, missed this earlier: I assume you wanted to finish this sentence with a period, or some expository text explaining why narrowing the scope of the change could be good, or more importantly, why it is not good, i.e. reiterating why it is important to support annotating (most) expressions. |
||
|
||
# Unresolved questions | ||
|
||
- Are the complications of allowing attributes on arbitrary | ||
expressions worth the benefits? | ||
Are the complications of allowing attributes on arbitrary | ||
expressions worth the benefits? | ||
|
||
The interaction with `if`/`else` chains are somewhat subtle, and it | ||
may be worth introducing "interior" and "exterior" attributes on `if`, or | ||
just disallowing them entirely. | ||
|
||
```rust | ||
#[cfg(not(foo))] | ||
if cond1 { | ||
} else #[cfg(not(bar))] if cond2 { | ||
} else #[cfg(not(baz))] { | ||
} | ||
``` | ||
|
||
- Which precedence should attributes have on arbitrary expressions? | ||
- `--cfg foo`: could be either removing the whole chain ("exterior") or | ||
equivalent to `if cond2 {} else {}` ("interior"). | ||
- `--cfg bar`: could be either `if cond1 {}` or `if cond1 {} else {}` | ||
- `--cfg baz`: equivalent to `if cond1 {} else if cond2 {}` (no subtlety). | ||
- `--cfg foo --cfg bar`: could be removing the whole chain or just | ||
the `else` branch (i.e. both `if` branches removed). | ||
|
||
This can be addressed by having `#[attr] if cond { ...` be an exterior | ||
attribute (applying to the whole `if`/`else` chain) and `if cond | ||
#[attr] { ... ` be an interior attribute (applying to only the current | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Markdown is interpreting this as a heading :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Haha, whoops. Fixed. |
||
`if` branch). |
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.
Could this include blocks?