Skip to content

Commit 27b59b3

Browse files
committed
Add suggestions for expressions in patterns
1 parent 6693ed5 commit 27b59b3

21 files changed

+1117
-86
lines changed

compiler/rustc_errors/src/lib.rs

+30
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,8 @@ pub enum StashKey {
535535
/// Query cycle detected, stashing in favor of a better error.
536536
Cycle,
537537
UndeterminedMacroResolution,
538+
/// Used by `Parser::maybe_recover_trailing_expr`
539+
ExprInPat,
538540
}
539541

540542
fn default_track_diagnostic<R>(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
@@ -837,6 +839,23 @@ impl<'a> DiagCtxtHandle<'a> {
837839
Some(Diag::new_diagnostic(self, diag))
838840
}
839841

842+
/// Steals a previously stashed error with the given `Span` and
843+
/// [`StashKey`] as the key, and cancels it if found.
844+
/// Panics if the found diagnostic's level isn't `Level::Error`.
845+
pub fn steal_err(&self, span: Span, key: StashKey, _: ErrorGuaranteed) -> bool {
846+
let key = (span.with_parent(None), key);
847+
// FIXME(#120456) - is `swap_remove` correct?
848+
self.inner
849+
.borrow_mut()
850+
.stashed_diagnostics
851+
.swap_remove(&key)
852+
.inspect(|(diag, guar)| {
853+
assert_eq!(diag.level, Error);
854+
assert!(guar.is_some())
855+
})
856+
.is_some()
857+
}
858+
840859
/// Steals a previously stashed error with the given `Span` and
841860
/// [`StashKey`] as the key, modifies it, and emits it. Returns `None` if
842861
/// no matching diagnostic is found. Panics if the found diagnostic's level
@@ -1281,6 +1300,17 @@ impl<'a> DiagCtxtHandle<'a> {
12811300
self.create_err(err).emit()
12821301
}
12831302

1303+
/// See [`DiagCtxtHandle::stash_diagnostic`] for details.
1304+
#[track_caller]
1305+
pub fn stash_err(
1306+
&'a self,
1307+
span: Span,
1308+
key: StashKey,
1309+
err: impl Diagnostic<'a>,
1310+
) -> ErrorGuaranteed {
1311+
self.create_err(err).stash(span, key).unwrap()
1312+
}
1313+
12841314
/// Ensures that an error is printed. See `Level::DelayedBug`.
12851315
//
12861316
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't

compiler/rustc_parse/messages.ftl

+14
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,20 @@ parse_unexpected_expr_in_pat =
778778
779779
.label = arbitrary expressions are not allowed in patterns
780780
781+
parse_unexpected_expr_in_pat_const_sugg = extract the expression into a `const` and refer to it
782+
783+
parse_unexpected_expr_in_pat_create_guard_sugg = check the value in an arm guard
784+
785+
parse_unexpected_expr_in_pat_inline_const_sugg = wrap the expression in a inline const (requires `{"#"}![feature(inline_const_pat)]`)
786+
787+
parse_unexpected_expr_in_pat_remove_let_sugg =
788+
remove the `let` if you meant to {$has_initializer ->
789+
[true] do an assignment
790+
*[false] evaluate an expression
791+
}
792+
793+
parse_unexpected_expr_in_pat_update_guard_sugg = check the value in the arm guard
794+
781795
parse_unexpected_if_with_if = unexpected `if` in the condition expression
782796
.suggestion = remove the `if`
783797

compiler/rustc_parse/src/errors.rs

+86
Original file line numberDiff line numberDiff line change
@@ -2424,6 +2424,92 @@ pub(crate) struct UnexpectedExpressionInPattern {
24242424
pub is_bound: bool,
24252425
}
24262426

2427+
#[derive(Subdiagnostic)]
2428+
pub(crate) enum UnexpectedExpressionInPatternSugg {
2429+
#[multipart_suggestion(
2430+
parse_unexpected_expr_in_pat_remove_let_sugg,
2431+
applicability = "maybe-incorrect",
2432+
style = "verbose"
2433+
)]
2434+
RemoveLet {
2435+
/// The span of the `let` keyword.
2436+
#[suggestion_part(code = "")]
2437+
let_span: Span,
2438+
/// The span of the type annotation.
2439+
#[suggestion_part(code = "")]
2440+
ty_span: Option<Span>,
2441+
/// `true` iff the `let` statement has an initializer.
2442+
has_initializer: bool,
2443+
},
2444+
2445+
#[multipart_suggestion(
2446+
parse_unexpected_expr_in_pat_create_guard_sugg,
2447+
applicability = "maybe-incorrect"
2448+
)]
2449+
CreateGuard {
2450+
/// The span of the `PatKind:Err` to be transformed into a `PatKind::Ident`.
2451+
#[suggestion_part(code = "{ident}")]
2452+
ident_span: Span,
2453+
/// The end of the match arm's pattern.
2454+
#[suggestion_part(code = " if {ident} == {expr}")]
2455+
pat_hi: Span,
2456+
/// The suggested identifier.
2457+
ident: String,
2458+
/// `ident_span`'s snippet.
2459+
expr: String,
2460+
},
2461+
2462+
#[multipart_suggestion(
2463+
parse_unexpected_expr_in_pat_update_guard_sugg,
2464+
applicability = "maybe-incorrect"
2465+
)]
2466+
UpdateGuard {
2467+
/// The span of the `PatKind:Err` to be transformed into a `PatKind::Ident`.
2468+
#[suggestion_part(code = "{ident}")]
2469+
ident_span: Span,
2470+
/// The beginning of the match arm guard's expression.
2471+
#[suggestion_part(code = "(")]
2472+
guard_lo: Span,
2473+
/// The end of the match arm guard's expression.
2474+
#[suggestion_part(code = ") && {ident} == {expr}")]
2475+
guard_hi: Span,
2476+
/// The suggested identifier.
2477+
ident: String,
2478+
/// `ident_span`'s snippet.
2479+
expr: String,
2480+
},
2481+
2482+
#[multipart_suggestion(
2483+
parse_unexpected_expr_in_pat_const_sugg,
2484+
applicability = "has-placeholders"
2485+
)]
2486+
Const {
2487+
/// The beginning of statement's line.
2488+
#[suggestion_part(code = "{indentation}const {ident}: _ = {expr};\n")]
2489+
stmt_lo: Span,
2490+
/// The span of the `PatKind:Err` to be transformed into a `PatKind::Ident`.
2491+
#[suggestion_part(code = "{ident}")]
2492+
ident_span: Span,
2493+
/// The suggested identifier.
2494+
ident: String,
2495+
/// `ident_span`'s snippet.
2496+
expr: String,
2497+
/// The statement's block's indentation.
2498+
indentation: String,
2499+
},
2500+
2501+
#[multipart_suggestion(
2502+
parse_unexpected_expr_in_pat_inline_const_sugg,
2503+
applicability = "maybe-incorrect"
2504+
)]
2505+
InlineConst {
2506+
#[suggestion_part(code = "const {{ ")]
2507+
start_span: Span,
2508+
#[suggestion_part(code = " }}")]
2509+
end_span: Span,
2510+
},
2511+
}
2512+
24272513
#[derive(Diagnostic)]
24282514
#[diag(parse_unexpected_paren_in_range_pat)]
24292515
pub(crate) struct UnexpectedParenInRangePat {

0 commit comments

Comments
 (0)