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

Accept m!{ .. }.method() and m!{ .. }? statements. #88690

Merged
merged 3 commits into from Sep 16, 2021

Conversation

@m-ou-se
Copy link
Member

@m-ou-se m-ou-se commented Sep 6, 2021

This PR fixes something that I keep running into when using quote!{}.into() in a proc macro to convert the proc_macro2::TokenStream to a proc_macro::TokenStream:

Before:

error: expected expression, found `.`
 --> src/lib.rs:6:6
  |
4 |     quote! {
5 |         ...
6 |     }.into()
  |      ^ expected expression

After:

(No output, compiles fine.)


Context:

For expressions like { 1 } and if true { 1 } else { 2 }, we accept them as full statements without a trailing ;, which means the following is not accepted:

{ 1 } - 1 // error

since that is parsed as two statements: { 1 } and -1. Syntactically correct, but the type of { 1 } should be () as there is no ;.

However, for specifically . and ? after the }, we do continue parsing it as an expression:

{ "abc" }.len(); // ok

For braced macro invocations, we do not do this:

vec![1, 2, 3].len(); // ok
vec!{1, 2, 3}.len(); // error

(It parses vec!{1, 2, 3} as a full statement, and then complains about .len() not being a valid expression.)

This PR changes this to also look for a . and ? after a braced macro invocation. We can be sure the macro is an expression and not a full statement in those cases, since no statement can start with a . or ?.

@rust-highfive
Copy link
Collaborator

@rust-highfive rust-highfive commented Sep 6, 2021

r? @nagisa

(rust-highfive has picked a reviewer for you, use r? to override)

@m-ou-se m-ou-se changed the title Macro braces dot question expr parse Accept m!{ .. }.method() and m!{ .. }? statements. Sep 6, 2021
@m-ou-se
Copy link
Member Author

@m-ou-se m-ou-se commented Sep 6, 2021

@rust-lang/lang I suppose this requires an FCP?

@petrochenkov petrochenkov self-assigned this Sep 6, 2021
@joshtriplett
Copy link
Member

@joshtriplett joshtriplett commented Sep 6, 2021

I think, before approving something like this, we'd want to know if this restriction is important for any particular reason (e.g. interactions with parsing and follow sets). I don't think it would be, given the examples you gave, but it'd be helpful to have some guidance from someone with clear knowledge of how macros interact with the parser.

For my part, assuming it wouldn't break anything, I think this seems reasonable.

@petrochenkov
Copy link
Contributor

@petrochenkov petrochenkov commented Sep 8, 2021

I think this is the right thing to do and don't see any reasons for braced macros m! { ... } to be different from blocks { ... } in this position.
This shouldn't break anything since we are only making previously illegal code legal, and I don't see issues with expansion either.

cc @Aaron1011 just in case

@petrochenkov petrochenkov removed their assignment Sep 8, 2021
@nikomatsakis
Copy link
Contributor

@nikomatsakis nikomatsakis commented Sep 8, 2021

+1 from me, I agree that this seems more consistent.

nagisa
nagisa approved these changes Sep 10, 2021
Copy link
Contributor

@nagisa nagisa left a comment

I'm okay with this change on the implementation side of things.

On the language design side of things I feel like with this adjustment we end up neither here nor there for this syntax element appears to be treated in a fairly inconsistent manner compared to the rest of Rust's syntactic constructs. That is it now acts kind of like an expression but only in very specific contexts. I think it would be a good idea to go all the way to making it act like all the other ExpressionWithBlocks.

compiler/rustc_parse/src/parser/stmt.rs Show resolved Hide resolved
@scottmcm
Copy link
Member

@scottmcm scottmcm commented Sep 10, 2021

+1 from me as well for making it consistent. Given that things like

let x = loop { break 7_u32 }.count_ones();

work, then those same things working after macro_rules with braces seems like the right choice.

@nagisa
Copy link
Contributor

@nagisa nagisa commented Sep 12, 2021

r=me with a negative test added. At this point a FCP seems redundant given that we already had +1 from 3/5 T-lang members.

@m-ou-se
Copy link
Member Author

@m-ou-se m-ou-se commented Sep 13, 2021

@bors r= nagisa

@bors
Copy link
Contributor

@bors bors commented Sep 13, 2021

📌 Commit 7d8d7a0 has been approved by ``

@m-ou-se
Copy link
Member Author

@m-ou-se m-ou-se commented Sep 13, 2021

@bors r-

@m-ou-se
Copy link
Member Author

@m-ou-se m-ou-se commented Sep 13, 2021

@bors r=nagisa

@bors
Copy link
Contributor

@bors bors commented Sep 13, 2021

📌 Commit 7d8d7a0 has been approved by nagisa

Manishearth added a commit to Manishearth/rust that referenced this issue Sep 14, 2021
…xpr-parse, r=nagisa

Accept `m!{ .. }.method()` and `m!{ .. }?` statements.

This PR fixes something that I keep running into when using `quote!{}.into()` in a proc macro to convert the `proc_macro2::TokenStream` to a `proc_macro::TokenStream`:

Before:

```
error: expected expression, found `.`
 --> src/lib.rs:6:6
  |
4 |     quote! {
5 |         ...
6 |     }.into()
  |      ^ expected expression
```

After:
```
```
(No output, compiles fine.)

---

Context:

For expressions like `{ 1 }` and `if true { 1 } else { 2 }`, we accept them as full statements without a trailing `;`, which means the following is not accepted:

```rust
{ 1 } - 1 // error
```

since that is parsed as two statements: `{ 1 }` and `-1`. Syntactically correct, but the type of `{ 1 }` should be `()` as there is no `;`.

However, for specifically `.` and `?` after the `}`, we do [continue parsing it as an expression](https://github.com/rust-lang/rust/blob/13db8440bbbe42870bc828d4ec3e965b38670277/compiler/rustc_parse/src/parser/expr.rs#L864-L876):

```rust
{ "abc" }.len(); // ok
```

For braced macro invocations, we do not do this:

```rust
vec![1, 2, 3].len(); // ok
vec!{1, 2, 3}.len(); // error
```

(It parses `vec!{1, 2, 3}` as a full statement, and then complains about `.len()` not being a valid expression.)

This PR changes this to also look for a `.` and `?` after a braced macro invocation. We can be sure the macro is an expression and not a full statement in those cases, since no statement can start with a `.` or `?`.
Manishearth added a commit to Manishearth/rust that referenced this issue Sep 14, 2021
…xpr-parse, r=nagisa

Accept `m!{ .. }.method()` and `m!{ .. }?` statements.

This PR fixes something that I keep running into when using `quote!{}.into()` in a proc macro to convert the `proc_macro2::TokenStream` to a `proc_macro::TokenStream`:

Before:

```
error: expected expression, found `.`
 --> src/lib.rs:6:6
  |
4 |     quote! {
5 |         ...
6 |     }.into()
  |      ^ expected expression
```

After:
```
```
(No output, compiles fine.)

---

Context:

For expressions like `{ 1 }` and `if true { 1 } else { 2 }`, we accept them as full statements without a trailing `;`, which means the following is not accepted:

```rust
{ 1 } - 1 // error
```

since that is parsed as two statements: `{ 1 }` and `-1`. Syntactically correct, but the type of `{ 1 }` should be `()` as there is no `;`.

However, for specifically `.` and `?` after the `}`, we do [continue parsing it as an expression](https://github.com/rust-lang/rust/blob/13db8440bbbe42870bc828d4ec3e965b38670277/compiler/rustc_parse/src/parser/expr.rs#L864-L876):

```rust
{ "abc" }.len(); // ok
```

For braced macro invocations, we do not do this:

```rust
vec![1, 2, 3].len(); // ok
vec!{1, 2, 3}.len(); // error
```

(It parses `vec!{1, 2, 3}` as a full statement, and then complains about `.len()` not being a valid expression.)

This PR changes this to also look for a `.` and `?` after a braced macro invocation. We can be sure the macro is an expression and not a full statement in those cases, since no statement can start with a `.` or `?`.
bors added a commit to rust-lang-ci/rust that referenced this issue Sep 14, 2021
…arth

Rollup of 9 pull requests

Successful merges:

 - rust-lang#87320 (Introduce -Z remap-cwd-prefix switch)
 - rust-lang#88619 (Remove `cfg(doc)` from std::os module reexports to fix rustdoc linking issues)
 - rust-lang#88690 (Accept `m!{ .. }.method()` and `m!{ .. }?` statements. )
 - rust-lang#88775 (Revert anon union parsing)
 - rust-lang#88781 (Tokenize emoji as if they were valid identifiers )
 - rust-lang#88841 (feat(rustc_typeck): suggest removing bad parens in `(recv.method)()`)
 - rust-lang#88892 (Move object safety suggestions to the end of the error)
 - rust-lang#88915 (`Wrapping<T>` has the same layout and ABI as `T`)
 - rust-lang#88933 (Remove implementation of `min_align_of` intrinsic)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
Manishearth added a commit to Manishearth/rust that referenced this issue Sep 14, 2021
…xpr-parse, r=nagisa

Accept `m!{ .. }.method()` and `m!{ .. }?` statements.

This PR fixes something that I keep running into when using `quote!{}.into()` in a proc macro to convert the `proc_macro2::TokenStream` to a `proc_macro::TokenStream`:

Before:

```
error: expected expression, found `.`
 --> src/lib.rs:6:6
  |
4 |     quote! {
5 |         ...
6 |     }.into()
  |      ^ expected expression
```

After:
```
```
(No output, compiles fine.)

---

Context:

For expressions like `{ 1 }` and `if true { 1 } else { 2 }`, we accept them as full statements without a trailing `;`, which means the following is not accepted:

```rust
{ 1 } - 1 // error
```

since that is parsed as two statements: `{ 1 }` and `-1`. Syntactically correct, but the type of `{ 1 }` should be `()` as there is no `;`.

However, for specifically `.` and `?` after the `}`, we do [continue parsing it as an expression](https://github.com/rust-lang/rust/blob/13db8440bbbe42870bc828d4ec3e965b38670277/compiler/rustc_parse/src/parser/expr.rs#L864-L876):

```rust
{ "abc" }.len(); // ok
```

For braced macro invocations, we do not do this:

```rust
vec![1, 2, 3].len(); // ok
vec!{1, 2, 3}.len(); // error
```

(It parses `vec!{1, 2, 3}` as a full statement, and then complains about `.len()` not being a valid expression.)

This PR changes this to also look for a `.` and `?` after a braced macro invocation. We can be sure the macro is an expression and not a full statement in those cases, since no statement can start with a `.` or `?`.
bors added a commit to rust-lang-ci/rust that referenced this issue Sep 14, 2021
…arth

Rollup of 8 pull requests

Successful merges:

 - rust-lang#87320 (Introduce -Z remap-cwd-prefix switch)
 - rust-lang#88619 (Remove `cfg(doc)` from std::os module reexports to fix rustdoc linking issues)
 - rust-lang#88690 (Accept `m!{ .. }.method()` and `m!{ .. }?` statements. )
 - rust-lang#88775 (Revert anon union parsing)
 - rust-lang#88781 (Tokenize emoji as if they were valid identifiers )
 - rust-lang#88841 (feat(rustc_typeck): suggest removing bad parens in `(recv.method)()`)
 - rust-lang#88915 (`Wrapping<T>` has the same layout and ABI as `T`)
 - rust-lang#88933 (Remove implementation of `min_align_of` intrinsic)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
Manishearth added a commit to Manishearth/rust that referenced this issue Sep 14, 2021
…xpr-parse, r=nagisa

Accept `m!{ .. }.method()` and `m!{ .. }?` statements.

This PR fixes something that I keep running into when using `quote!{}.into()` in a proc macro to convert the `proc_macro2::TokenStream` to a `proc_macro::TokenStream`:

Before:

```
error: expected expression, found `.`
 --> src/lib.rs:6:6
  |
4 |     quote! {
5 |         ...
6 |     }.into()
  |      ^ expected expression
```

After:
```
```
(No output, compiles fine.)

---

Context:

For expressions like `{ 1 }` and `if true { 1 } else { 2 }`, we accept them as full statements without a trailing `;`, which means the following is not accepted:

```rust
{ 1 } - 1 // error
```

since that is parsed as two statements: `{ 1 }` and `-1`. Syntactically correct, but the type of `{ 1 }` should be `()` as there is no `;`.

However, for specifically `.` and `?` after the `}`, we do [continue parsing it as an expression](https://github.com/rust-lang/rust/blob/13db8440bbbe42870bc828d4ec3e965b38670277/compiler/rustc_parse/src/parser/expr.rs#L864-L876):

```rust
{ "abc" }.len(); // ok
```

For braced macro invocations, we do not do this:

```rust
vec![1, 2, 3].len(); // ok
vec!{1, 2, 3}.len(); // error
```

(It parses `vec!{1, 2, 3}` as a full statement, and then complains about `.len()` not being a valid expression.)

This PR changes this to also look for a `.` and `?` after a braced macro invocation. We can be sure the macro is an expression and not a full statement in those cases, since no statement can start with a `.` or `?`.
bors added a commit to rust-lang-ci/rust that referenced this issue Sep 14, 2021
…arth

Rollup of 8 pull requests

Successful merges:

 - rust-lang#87320 (Introduce -Z remap-cwd-prefix switch)
 - rust-lang#88619 (Remove `cfg(doc)` from std::os module reexports to fix rustdoc linking issues)
 - rust-lang#88690 (Accept `m!{ .. }.method()` and `m!{ .. }?` statements. )
 - rust-lang#88775 (Revert anon union parsing)
 - rust-lang#88841 (feat(rustc_typeck): suggest removing bad parens in `(recv.method)()`)
 - rust-lang#88907 (Highlight the `const fn` if error happened because of a bound on the impl block)
 - rust-lang#88915 (`Wrapping<T>` has the same layout and ABI as `T`)
 - rust-lang#88933 (Remove implementation of `min_align_of` intrinsic)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
Manishearth added a commit to Manishearth/rust that referenced this issue Sep 15, 2021
…xpr-parse, r=nagisa

Accept `m!{ .. }.method()` and `m!{ .. }?` statements.

This PR fixes something that I keep running into when using `quote!{}.into()` in a proc macro to convert the `proc_macro2::TokenStream` to a `proc_macro::TokenStream`:

Before:

```
error: expected expression, found `.`
 --> src/lib.rs:6:6
  |
4 |     quote! {
5 |         ...
6 |     }.into()
  |      ^ expected expression
```

After:
```
```
(No output, compiles fine.)

---

Context:

For expressions like `{ 1 }` and `if true { 1 } else { 2 }`, we accept them as full statements without a trailing `;`, which means the following is not accepted:

```rust
{ 1 } - 1 // error
```

since that is parsed as two statements: `{ 1 }` and `-1`. Syntactically correct, but the type of `{ 1 }` should be `()` as there is no `;`.

However, for specifically `.` and `?` after the `}`, we do [continue parsing it as an expression](https://github.com/rust-lang/rust/blob/13db8440bbbe42870bc828d4ec3e965b38670277/compiler/rustc_parse/src/parser/expr.rs#L864-L876):

```rust
{ "abc" }.len(); // ok
```

For braced macro invocations, we do not do this:

```rust
vec![1, 2, 3].len(); // ok
vec!{1, 2, 3}.len(); // error
```

(It parses `vec!{1, 2, 3}` as a full statement, and then complains about `.len()` not being a valid expression.)

This PR changes this to also look for a `.` and `?` after a braced macro invocation. We can be sure the macro is an expression and not a full statement in those cases, since no statement can start with a `.` or `?`.
bors added a commit to rust-lang-ci/rust that referenced this issue Sep 15, 2021
…arth

Rollup of 7 pull requests

Successful merges:

 - rust-lang#88690 (Accept `m!{ .. }.method()` and `m!{ .. }?` statements. )
 - rust-lang#88775 (Revert anon union parsing)
 - rust-lang#88841 (feat(rustc_typeck): suggest removing bad parens in `(recv.method)()`)
 - rust-lang#88907 (Highlight the `const fn` if error happened because of a bound on the impl block)
 - rust-lang#88915 (`Wrapping<T>` has the same layout and ABI as `T`)
 - rust-lang#88933 (Remove implementation of `min_align_of` intrinsic)
 - rust-lang#88951 (Update books)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
bors added a commit to rust-lang-ci/rust that referenced this issue Sep 15, 2021
…arth

Rollup of 7 pull requests

Successful merges:

 - rust-lang#88690 (Accept `m!{ .. }.method()` and `m!{ .. }?` statements. )
 - rust-lang#88775 (Revert anon union parsing)
 - rust-lang#88841 (feat(rustc_typeck): suggest removing bad parens in `(recv.method)()`)
 - rust-lang#88907 (Highlight the `const fn` if error happened because of a bound on the impl block)
 - rust-lang#88915 (`Wrapping<T>` has the same layout and ABI as `T`)
 - rust-lang#88933 (Remove implementation of `min_align_of` intrinsic)
 - rust-lang#88951 (Update books)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
bors added a commit to rust-lang-ci/rust that referenced this issue Sep 16, 2021
…arth

Rollup of 8 pull requests

Successful merges:

 - rust-lang#87320 (Introduce -Z remap-cwd-prefix switch)
 - rust-lang#88690 (Accept `m!{ .. }.method()` and `m!{ .. }?` statements. )
 - rust-lang#88775 (Revert anon union parsing)
 - rust-lang#88841 (feat(rustc_typeck): suggest removing bad parens in `(recv.method)()`)
 - rust-lang#88907 (Highlight the `const fn` if error happened because of a bound on the impl block)
 - rust-lang#88915 (`Wrapping<T>` has the same layout and ABI as `T`)
 - rust-lang#88933 (Remove implementation of `min_align_of` intrinsic)
 - rust-lang#88951 (Update books)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 4b56840 into rust-lang:master Sep 16, 2021
10 checks passed
@rustbot rustbot added this to the 1.57.0 milestone Sep 16, 2021
@m-ou-se m-ou-se deleted the macro-braces-dot-question-expr-parse branch Sep 17, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

9 participants