Commit Graph

615 Commits

Author SHA1 Message Date
Moritz Hedtke
7fada167f9 Make LetChainsPolicy public for rustfmt usage 2025-09-06 18:01:31 +02:00
Moritz Hedtke
d8df6312d5 Make Parser::parse_for_head public for rustfmt usage 2025-09-01 17:30:47 +02:00
Jonathan Brouwer
f328709276 Improve error messages around invalid literals in attribute arguments
Signed-off-by: Jonathan Brouwer <jonathantbrouwer@gmail.com>
2025-08-28 20:05:04 +02:00
Nicholas Nethercote
a06c3887bd Remove the lifetime from ExpTokenPair/SeqSep.
`TokenKind` now impls `Copy`, so we can store it directly rather than a
reference.
2025-08-25 08:02:52 +10:00
Jacob Pratt
2dbd411d22 Rollup merge of #144897 - fee1-dead-contrib:raw_lifetimes_printing, r=fmease
print raw lifetime idents with r#

This replaces rust-lang/rust#143185 and fixes rust-lang/rust#143150

cc ``@fmease``
2025-08-22 22:00:47 -04:00
Jonathan Brouwer
549314bdb7 Rewrite the new attribute parser 2025-08-22 08:38:37 +02:00
Deadbeef
4970127c33 address review comments 2025-08-22 13:16:44 +08:00
Deadbeef
30bb7045d6 don't print invalid labels with r# 2025-08-22 12:58:37 +08:00
Jacob Pratt
f49d69093e Rollup merge of #145604 - compiler-errors:static-closure, r=fmease
Gate static closures behind a parser feature

I'd like to gate `static ||` closures behind a feature gate, since we shouldn't allow people to take advantage of this syntax if it's currently unstable. Right now, since it's only rejected after ast lowering, it's accessible to macros.

Let's crater this to see if we can claw it back without breaking anyone's code.
2025-08-21 17:57:52 -04:00
Michael Goulet
db0c825d2c Gate static coroutines behind a parser feature 2025-08-19 13:12:31 +00:00
León Orell Valerian Liehr
f8f7c27d4f Clean up parsers related to generic bounds 2025-08-16 16:15:58 +02:00
bors
41ede7bd9b Auto merge of #145146 - fee1-dead-contrib:push-zmqrkurlzrxy, r=nnethercote
remove `P`

Previous work: rust-lang/rust#141603
MCP: https://github.com/rust-lang/compiler-team/issues/878

cc `@nnethercote`
2025-08-09 23:27:55 +00:00
Deadbeef
ad1113f87e remove P 2025-08-09 15:47:01 +08:00
Michael Goulet
b2d524c43d Recover for PAT = EXPR {} 2025-08-08 18:46:09 +00:00
Michael Goulet
51cd9b564f Consider operator's span when computing binop expr span 2025-07-31 02:28:11 +00:00
Michael Goulet
2db97b2f7d Account for .yield in illegal postfix operator message 2025-07-28 16:09:59 +00:00
Cameron Steffen
dc9879cb3d Remove let_chains feature 2025-06-30 07:49:20 -05:00
Michael Goulet
94e9973b92 Add Ident::is_non_reserved_ident 2025-06-26 18:11:14 +00:00
Jubilee
4f477427b8 Rollup merge of #135731 - frank-king:feature/pin-borrow, r=eholk,traviscross
Implement parsing of pinned borrows

This PR implements part of #130494.

EDIT: It introduces `&pin mut $place` and `&pin const $place` as sugars for `std::pin::pin!($place)` and its shared reference equivalent, except that `$place` will not be moved when borrowing. The borrow check will be in charge of enforcing places cannot be moved or mutably borrowed since being pinned till dropped.

### Implementation steps:
- [x] parse the `&pin mut $place` and `&pin const $place` syntaxes
- [ ] borrowck of `&pin mut|const`
- [ ] support autoref of `&pin mut|const` when needed
2025-06-24 19:45:29 -07:00
Frank King
e627f88f88 Implement pinned borrows, part of pin_ergonomics 2025-06-15 10:21:29 +08:00
Deadbeef
5f0dd44b3b avoid &mut P<T> in visit_expr etc methods 2025-06-12 17:36:03 +08:00
Lukas Wirth
edc405d383 Add expectation for { when parsing lone coroutine qualifiers 2025-06-11 17:11:58 +02:00
Guillaume Gomez
93ca0af08c Rollup merge of #141603 - nnethercote:reduce-P, r=fee1-dead
Reduce `ast::ptr::P` to a typedef of `Box`

As per the MCP at https://github.com/rust-lang/compiler-team/issues/878.

r? `@fee1-dead`
2025-06-06 23:53:16 +02:00
Nicholas Nethercote
04391045d0 Remove Path::is_ident.
It checks that a path has a single segment that matches the given
symbol, and that there are zero generic arguments. It has a single use.

We also have `impl PartialEq<Symbol> for Path` which does exactly the
same thing *except* it doesn't check for zero generic arguments, which
seems like an oversight. It has numerous uses.

This commit removes `Path::is_ident`, adds a test for zero generic
arguments to `PartialEq<Symbol> for Path`, and changes the single use of
`is_ident` to instead use `==`.
2025-06-03 15:21:33 +10:00
Nicholas Nethercote
991c91fdaa Reduce P<T> to a typedef of Box<T>.
Keep the `P` constructor function for now, to minimize immediate churn.

All the `into_inner` calls are removed, which is nice.
2025-05-27 13:29:24 +10:00
Nicholas Nethercote
0f285e346f Remove the one use of P<[T]>.
A `Vec` is fine, the additional word (vector vs. boxed slice) doesn't
matter here.
2025-05-27 02:54:18 +10:00
yukang
5f8954bc41 Fix the issue of typo of comma in arm parsing 2025-05-16 12:40:04 +02:00
Nicholas Nethercote
0984db553d Remove Ident::empty.
All uses have been removed. And it's nonsensical: an identifier by
definition has at least one char.

The commits adds an is-non-empty assertion to `Ident::new` to enforce
this, and converts some `Ident` constructions to use `Ident::new`.
Adding the assertion requires making `Ident::new` and
`Ident::with_dummy_span` non-const, which is no great loss.

The commit amends a couple of places that do path splitting to ensure no
empty identifiers are created.
2025-05-09 13:57:49 +10:00
Kivooeo
f072d30741 resolved conflict 2025-04-25 17:02:59 +05:00
Chris Denton
15f8847a25 Rollup merge of #140144 - nnethercote:fix-140098, r=petrochenkov
Handle another negated literal in `eat_token_lit`.

Extends the change from #139653, which was on expressions, to literals.

Fixes #140098.

r? ``@petrochenkov``
2025-04-22 15:24:08 +00:00
bors
8bf5a8d12f Auto merge of #132833 - est31:stabilize_let_chains, r=fee1-dead
Stabilize let chains in the 2024 edition

# Stabilization report

This proposes the stabilization of `let_chains` ([tracking issue], [RFC 2497]) in the [2024 edition] of Rust.

[tracking issue]: https://github.com/rust-lang/rust/issues/53667
[RFC 2497]: https://github.com/rust-lang/rfcs/pull/2497
[2024 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/index.html

## What is being stabilized

The ability to `&&`-chain `let` statements inside `if` and `while` is being stabilized, allowing intermixture with boolean expressions. The patterns inside the `let` sub-expressions can be irrefutable or refutable.

```Rust
struct FnCall<'a> {
    fn_name: &'a str,
    args: Vec<i32>,
}

fn is_legal_ident(s: &str) -> bool {
    s.chars()
        .all(|c| ('a'..='z').contains(&c) || ('A'..='Z').contains(&c))
}

impl<'a> FnCall<'a> {
    fn parse(s: &'a str) -> Option<Self> {
        if let Some((fn_name, after_name)) = s.split_once("(")
            && !fn_name.is_empty()
            && is_legal_ident(fn_name)
            && let Some((args_str, "")) = after_name.rsplit_once(")")
        {
            let args = args_str
                .split(',')
                .map(|arg| arg.parse())
                .collect::<Result<Vec<_>, _>>();
            args.ok().map(|args| FnCall { fn_name, args })
        } else {
            None
        }
    }
    fn exec(&self) -> Option<i32> {
        let iter = self.args.iter().copied();
        match self.fn_name {
            "sum" => Some(iter.sum()),
            "max" => iter.max(),
            "min" => iter.min(),
            _ => None,
        }
    }
}

fn main() {
    println!("{:?}", FnCall::parse("sum(1,2,3)").unwrap().exec());
    println!("{:?}", FnCall::parse("max(4,5)").unwrap().exec());
}
```

The feature will only be stabilized for the 2024 edition and future editions. Users of past editions will get an error with a hint to update the edition.

closes #53667

## Why 2024 edition?

Rust generally tries to ship new features to all editions. So even the oldest editions receive the newest features. However, sometimes a feature requires a breaking change so much that offering the feature without the breaking change makes no sense. This occurs rarely, but has happened in the 2018 edition already with `async` and `await` syntax. It required an edition boundary in order for `async`/`await` to become keywords, and the entire feature foots on those keywords.

In the instance of let chains, the issue is the drop order of `if let` chains. If we want `if let` chains to be compatible with `if let`, drop order makes it hard for us to [generate correct MIR]. It would be strange to have different behaviour for `if let ... {}` and `if true && let ... {}`. So it's better to [stay consistent with `if let`].

In edition 2024, [drop order changes] have been introduced to make `if let` temporaries be lived more shortly. These changes also affected `if let` chains. These changes make sense even if you don't take the `if let` chains MIR generation problem into account. But if we want to use them as the solution to the MIR generation problem, we need to restrict let chains to edition 2024 and beyond: for let chains, it's not just a change towards more sensible behaviour, but one required for correct function.

[generate correct MIR]: https://github.com/rust-lang/rust/issues/104843
[stay consistent with `if let`]: https://github.com/rust-lang/rust/pull/103293#issuecomment-1293408574
[drop order changes]: https://github.com/rust-lang/rust/issues/124085

## Introduction considerations

As edition 2024 is very new, this stabilization PR only makes it possible to use let chains on 2024 without that feature gate, it doesn't mark that feature gate as stable/removed. I would propose to continue offering the `let_chains` feature (behind a feature gate) for a limited time (maybe 3 months after stabilization?) on older editions to allow nightly users to adopt edition 2024 at their own pace. After that, the feature gate shall be marked as *stabilized*, not removed, and replaced by an error on editions 2021 and below.

## Implementation history

* History from before March 14, 2022 can be found in the [original stabilization PR] that was reverted.
* https://github.com/rust-lang/rust/pull/94927
* https://github.com/rust-lang/rust/pull/94951
* https://github.com/rust-lang/rust/pull/94974
* https://github.com/rust-lang/rust/pull/95008
* https://github.com/rust-lang/rust/pull/97295
* https://github.com/rust-lang/rust/pull/98633
* https://github.com/rust-lang/rust/pull/99731
* https://github.com/rust-lang/rust/pull/102394
* https://github.com/rust-lang/rust/pull/100526
* https://github.com/rust-lang/rust/pull/100538
* https://github.com/rust-lang/rust/pull/102998
* https://github.com/rust-lang/rust/pull/103405
* https://github.com/rust-lang/rust/pull/103293
* https://github.com/rust-lang/rust/pull/107251
* https://github.com/rust-lang/rust/pull/110568
* https://github.com/rust-lang/rust/pull/115677
* https://github.com/rust-lang/rust/pull/117743
* https://github.com/rust-lang/rust/pull/117770
* https://github.com/rust-lang/rust/pull/118191
* https://github.com/rust-lang/rust/pull/119554
* https://github.com/rust-lang/rust/pull/129394
* https://github.com/rust-lang/rust/pull/132828
* https://github.com/rust-lang/reference/pull/1179
* https://github.com/rust-lang/reference/pull/1251
* https://github.com/rust-lang/rustfmt/pull/5910

[original stabilization PR]: https://github.com/rust-lang/rust/pull/94927

## Adoption history

### In the compiler

* History before March 14, 2022 can be found in the [original stabilization PR].
* https://github.com/rust-lang/rust/pull/115983
* https://github.com/rust-lang/rust/pull/116549
* https://github.com/rust-lang/rust/pull/116688

### Outside of the compiler

* https://github.com/rust-lang/rust-clippy/pull/11750
* [rspack](https://github.com/web-infra-dev/rspack)
* [risingwave](https://github.com/risingwavelabs/risingwave)
* [dylint](https://github.com/trailofbits/dylint)
* [convex-backend](https://github.com/get-convex/convex-backend)
* [tikv](https://github.com/tikv/tikv)
* [Daft](https://github.com/Eventual-Inc/Daft)
* [greptimedb](https://github.com/GreptimeTeam/greptimedb)

## Tests

<details>

### Intentional restrictions

[`partially-macro-expanded.rs`](4adafcf40a/tests/ui/rfcs/rfc-2294-if-let-guard/partially-macro-expanded.rs), [`macro-expanded.rs`](4adafcf40a/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.rs): it is possible to use macros to expand to both the pattern and the expression inside a let chain, but not to the entire `let pat = expr` operand.
[`parens.rs`](4adafcf40a/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs): `if (let pat = expr)` is not allowed in chains
[`ensure-that-let-else-does-not-interact-with-let-chains.rs`](4adafcf40a/tests/ui/rfcs/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs): `let...else` doesn't support chaining.

### Overlap with match guards

[`move-guard-if-let-chain.rs`](4adafcf40a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs): test for the `use moved value` error working well in match guards. could maybe be extended with let chains that have more than one `let`
[`shadowing.rs`](4adafcf40a/tests/ui/rfcs/rfc-2294-if-let-guard/shadowing.rs): shadowing in if let guards works as expected
[`ast-validate-guards.rs`](4adafcf40a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs): let chains in match guards require the match guards feature gate

### Simple cases from the early days

PR #88642 has added some tests with very simple usages of `let else`, mostly as regression tests to early bugs.

[`then-else-blocks.rs`](4adafcf40a/tests/ui/rfcs/rfc-2497-if-let-chains/then-else-blocks.rs)
[`ast-lowering-does-not-wrap-let-chains.rs`](4adafcf40a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs)
[`issue-90722.rs`](4adafcf40a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-90722.rs)
[`issue-92145.rs`](4adafcf40a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-92145.rs)

### Drop order/MIR scoping tests

[`issue-100276.rs`](4adafcf40a/tests/ui/drop/issue-100276.rs): let expressions on RHS aren't terminating scopes
[`drop_order.rs`](4adafcf40a/tests/ui/drop/drop_order.rs): exhaustive temporary drop order test for various Rust constructs, including let chains
[`scope.rs`](4adafcf40a/tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs): match guard scoping test
[`drop-scope.rs`](4adafcf40a/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs): another match guard scoping test, ensuring that temporaries in if-let guards live for the arm
[`drop_order_if_let_rescope.rs`](4adafcf40a/tests/ui/drop/drop_order_if_let_rescope.rs): if let rescoping on edition 2024, including chains
[`mir_let_chains_drop_order.rs`](4adafcf40a/tests/ui/mir/mir_let_chains_drop_order.rs): comprehensive drop order test for let chains, distinguishes editions 2021 and 2024.
[`issue-99938.rs`](4adafcf40a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-99938.rs), [`issue-99852.rs`](4adafcf40a/tests/ui/mir/issue-99852.rs) both bad MIR ICEs fixed by #102394

### Linting

[`irrefutable-lets.rs`](4adafcf40a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs): trailing and leading irrefutable let patterns get linted for, others don't. The lint is turned off for `else if`.
[`issue-121070-let-range.rs`](4adafcf40a/tests/ui/lint/issue-121070-let-range.rs): regression test for false positive of the unused parens lint, precedence requires the `()`s here

### Parser: intentional restrictions

[`disallowed-positions.rs`](2128d8df0e/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs): `let` in expression context is rejected everywhere except at the top level
[`invalid-let-in-a-valid-let-context.rs`](4adafcf40a/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs): nested `let` is not allowed (let's are no legal expressions just because they are allowed in `if` and `while`).

### Parser: recovery

[`issue-103381.rs`](4adafcf40a/tests/ui/parser/issues/issue-103381.rs): Graceful recovery of incorrect chaining of `if` and `if let`
[`semi-in-let-chain.rs`](4adafcf40a/tests/ui/parser/semi-in-let-chain.rs): Ensure that stray `;`s in let chains give nice errors (`if_chain!` users might be accustomed to `;`s)
[`deli-ident-issue-1.rs`](4adafcf40a/tests/ui/parser/deli-ident-issue-1.rs), [`brace-in-let-chain.rs`](4adafcf40a/tests/ui/parser/brace-in-let-chain.rs): Ensure that stray unclosed `{`s in let chains give nice errors and hints

### Misc

[`conflicting_bindings.rs`](4adafcf40a/tests/ui/pattern/usefulness/conflicting_bindings.rs): the conflicting bindings check also works in let chains. Personally, I'd extend it to chains with multiple let's as well.
[`let-chains-attr.rs`](4adafcf40a/tests/ui/expr/if/attrs/let-chains-attr.rs): attributes work on let chains

### Tangential tests with `#![feature(let_chains)]`

[`if-let.rs`](4adafcf40a/tests/coverage/branch/if-let.rs): MC/DC coverage tests for let chains
[`logical_or_in_conditional.rs`](4adafcf40a/tests/mir-opt/building/logical_or_in_conditional.rs): not really about let chains, more about dropping/scoping behaviour of `||`
[`stringify.rs`](4adafcf40a/tests/ui/macros/stringify.rs): exhaustive test of the `stringify` macro
[`expanded-interpolation.rs`](4adafcf40a/tests/ui/unpretty/expanded-interpolation.rs), [`expanded-exhaustive.rs`](4adafcf40a/tests/ui/unpretty/expanded-exhaustive.rs): Exhaustive test of `-Zunpretty`
[`diverges-not.rs`](4adafcf40a/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs): Never type, mostly tangential to let chains

</details>

## Possible future work

* There is proposals to allow `if let Pat(bindings) = expr {}` to be written as `if expr is Pat(bindings) {}` ([RFC 3573]). `if let` chains are a natural extension of the already existing `if let` syntax, and I'd argue orthogonal towards `is` syntax.
  * https://github.com/rust-lang/lang-team/issues/297
* One could have similar chaining inside `let ... else` statements. There is no proposed RFC for this however, nor is it implemented on nightly.
* Match guards have the `if` keyword as well, but on stable Rust, they don't support `let`. The functionality is available via an unstable feature ([`if_let_guard` tracking issue]). Stabilization of let chains affects this feature in so far as match guards containing let chains now only need the `if_let_guard` feature gate be present instead of also the `let_chains` feature (NOTE: this PR doesn't implement this simplification, it's left for future work).

[RFC 3573]: https://github.com/rust-lang/rfcs/pull/3573
[`if_let_guard` tracking issue]: https://github.com/rust-lang/rust/issues/51114

## Open questions / blockers

- [ ] bad recovery if you don't put a `let` (I don't think this is a blocker): [#117977](https://github.com/rust-lang/rust/issues/117977)
- [x] An instance where a temporary lives shorter than with nested ifs, breaking compilation: [#103476](https://github.com/rust-lang/rust/issues/103476). Personally I don't think this is a blocker either, as it's an edge case. Edit: turns out to not reproduce in edition 2025 any more, due to let rescoping. regression test added in #133093
- [x] One should probably extend the tests for `move-guard-if-let-chain.rs` and `conflicting_bindings.rs` to have chains with multiple let's: done in 133093
- [x] Parsing rejection tests: addressed by https://github.com/rust-lang/rust/pull/132828
- [x] [Style](https://rust-lang.zulipchat.com/#narrow/channel/346005-t-style/topic/let.20chains.20stabilization.20and.20formatting): https://github.com/rust-lang/rust/pull/139456
- [x] https://github.com/rust-lang/rust/issues/86730 explicitly mentions `let_else`. I think we can live with `let pat = expr` not evaluating as `expr` for macro_rules macros, especially given that `let pat = expr` is not a legal expression anywhere except inside `if` and `while`.
- [x] Documentation in the reference: https://github.com/rust-lang/reference/pull/1740
- [x] Add chapter to the Rust 2024 [edition guide]: https://github.com/rust-lang/edition-guide/pull/337
- [x] Resolve open questions on desired drop order.

[original reference PR]: https://github.com/rust-lang/reference/pull/1179
[edition guide]: https://github.com/rust-lang/edition-guide
2025-04-22 07:54:10 +00:00
Nicholas Nethercote
6be270be0c Handle another negated literal in eat_token_lit.
Extends the change from #139653, which was on expressions, to literals.

Fixes #140098.
2025-04-22 15:08:32 +10:00
bors
fae7785b60 Auto merge of #139897 - nnethercote:rm-OpenDelim-CloseDelim, r=petrochenkov
Remove `token::{Open,Close}Delim`

By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.

PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.

This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
  pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
  `Delimiter` values to `TokenKind`.

Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
-   } else if self.token != token::CloseDelim(Delimiter::Brace) {
+   } else if self.token != token::CloseBrace {
```

r? `@petrochenkov`
2025-04-22 01:15:06 +00:00
Nicholas Nethercote
bf8ce32558 Remove token::{Open,Close}Delim.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.

PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.

This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
  pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
  `Delimiter` values to `TokenKind`.

Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
-   } else if self.token != token::CloseDelim(Delimiter::Brace) {
+   } else if self.token != token::CloseBrace {
```
2025-04-21 07:35:56 +10:00
est31
5258cb76a5 Don't call ungate_last 2025-04-20 23:14:55 +02:00
Chris Denton
db98b72e34 Rollup merge of #137454 - mu001999-contrib:fix-137414, r=wesleywiser
not lint break with label and unsafe block

fixes #137414

we can't label unsafe blocks, so that we can do not lint them
2025-04-19 14:01:36 +00:00
est31
d75f8cde2f Also allow let chains in match guards 2025-04-18 15:57:29 +02:00
est31
2e61af2fca Stabilize let chains on edition 2024 2025-04-18 14:21:14 +02:00
Matthias Krüger
bf49dfc943 Rollup merge of #139392 - compiler-errors:raw-expr, r=oli-obk
Detect and provide suggestion for `&raw EXPR`

When emitting an error in the parser, and we detect that the previous token was `raw` and we *could* have consumed `const`/`mut`, suggest that this may have been a mistyped raw ref expr. To do this, we add `const`/`mut` to the expected token set when parsing `&raw` as an expression (which does not affect the "good path" of parsing, for the record).

This is kind of a rudimentary error improvement, since it doesn't actually attempt to recover anything, leading to some other knock-on errors b/c we still treat `&raw` as the expression that was parsed... but at least we add the suggestion! I don't think the parser grammar means we can faithfully recover `&raw EXPR` early, i.e. during `parse_expr_borrow`.

Fixes #133231
2025-04-14 18:15:31 +02:00
bors
f836ae4e66 Auto merge of #124141 - nnethercote:rm-Nonterminal-and-TokenKind-Interpolated, r=petrochenkov
Remove `Nonterminal` and `TokenKind::Interpolated`

A third attempt at this; the first attempt was #96724 and the second was #114647.

r? `@ghost`
2025-04-14 03:56:55 +00:00
Nicholas Nethercote
d25c8a8ade Handle a negated literal in eat_token_lit.
Fixes #139495.
2025-04-11 10:57:36 +10:00
Michael Goulet
6dfbe7c986 Detect and provide suggestion for &raw EXPR 2025-04-04 21:36:12 +00:00
Guillaume Gomez
aff2bc7a88 Replace rustc_lexer/unescape with rustc-literal-escaper crate 2025-04-04 14:44:45 +02:00
Nicholas Nethercote
ddcb370bc6 Tighten up assignment operator representations.
In the AST, currently we use `BinOpKind` within `ExprKind::AssignOp` and
`AssocOp::AssignOp`, even though this allows some nonsensical
combinations. E.g. there is no `&&=` operator. Likewise for HIR and
THIR.

This commit introduces `AssignOpKind` which only includes the ten
assignable operators, and uses it in `ExprKind::AssignOp` and
`AssocOp::AssignOp`. (And does similar things for `hir::ExprKind` and
`thir::ExprKind`.) This avoids the possibility of nonsensical
combinations, as seen by the removal of the `bug!` case in
`lang_item_for_binop`.

The commit is mostly plumbing, including:
- Adds an `impl From<AssignOpKind> for BinOpKind` (AST) and `impl
  From<AssignOp> for BinOp` (MIR/THIR).
- `BinOpCategory` can now be created from both `BinOpKind` and
  `AssignOpKind`.
- Replaces the `IsAssign` type with `Op`, which has more information and
  a few methods.
- `suggest_swapping_lhs_and_rhs`: moves the condition to the call site,
  it's easier that way.
- `check_expr_inner`: had to factor out some code into a separate
  method.

I'm on the fence about whether avoiding the nonsensical combinations is
worth the extra code.
2025-04-03 10:23:03 +11:00
Nicholas Nethercote
4d8f7577b5 Impl Copy for Token and TokenKind. 2025-04-02 16:16:49 +11:00
Nicholas Nethercote
bb495d6d3e Remove NtBlock, Nonterminal, and TokenKind::Interpolated.
`NtBlock` is the last remaining variant of `Nonterminal`, so once it is
gone then `Nonterminal` can be removed as well.
2025-04-02 16:07:02 +11:00
Nicholas Nethercote
592d113ff2 Fix problem causing rusqlite compilation to OOM.
This makes the expression re-parsing more like how it's originally done
in `parse_nonterminal`.
2025-04-02 06:21:18 +11:00
Nicholas Nethercote
d59b17c5cd Remove Token::uninterpolated_span.
In favour of the similar method on `Parser`, which works on things
other than identifiers and lifetimes.
2025-04-02 06:21:16 +11:00
Nicholas Nethercote
49ed25b5d2 Remove NtExpr and NtLiteral.
Notes about tests:
- tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs: some messages are
  now duplicated due to repeated parsing.

- tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs: ditto.

- `tests/ui/proc-macro/macro-rules-derive-cfg.rs`: the diff looks large
  but the only difference is the insertion of a single
  invisible-delimited group around a metavar.

- `tests/ui/attributes/nonterminal-expansion.rs`: a slight span
  degradation, somehow related to the recent massive attr parsing
  rewrite (#135726). I couldn't work out exactly what is going wrong,
  but I don't think it's worth holding things up for a single slightly
  suboptimal error message.
2025-04-02 06:20:35 +11:00
Matthias Krüger
0a579d5247 Rollup merge of #138749 - compiler-errors:closure-recovery, r=fmease
Fix closure recovery for missing block when return type is specified

Firstly, fix the `is_array_like_block` condition to make sure we're actually recovering a mistyped *block* rather than some other delimited expression. This fixes #138748.

Secondly, split out the recovery of missing braces on a closure body into a separate recovery. Right now, the suggestion `"you might have meant to write this as part of a block"` originates from `suggest_fixes_misparsed_for_loop_head`, which feels kinda brittle and coincidental since AFAICT that recovery wasn't ever really intended to fix this.

We also can make this `MachineApplicable` in this case.

Fixes #138748

r? `@fmease` or reassign if you're busy/don't wanna review this
2025-03-31 14:36:21 +02:00