Skip to content

Commit 20303c1

Browse files
committed
Add suggestions for expressions in patterns
1 parent 4b7ce0e commit 20303c1

21 files changed

+1147
-85
lines changed

compiler/rustc_errors/src/lib.rs

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

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

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

1304+
/// See [`DiagCtxtHandle::stash_diagnostic`] for details.
1305+
#[track_caller]
1306+
pub fn stash_err(
1307+
&'a self,
1308+
span: Span,
1309+
key: StashKey,
1310+
err: impl Diagnostic<'a>,
1311+
) -> ErrorGuaranteed {
1312+
self.create_err(err).stash(span, key).unwrap()
1313+
}
1314+
12851315
/// Ensures that an error is printed. See `Level::DelayedBug`.
12861316
//
12871317
// 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
@@ -791,6 +791,20 @@ parse_unexpected_expr_in_pat =
791791
792792
.label = arbitrary expressions are not allowed in patterns
793793
794+
parse_unexpected_expr_in_pat_const_sugg = extract the expression into a `const` and refer to it
795+
796+
parse_unexpected_expr_in_pat_create_guard_sugg = check the value in an arm guard
797+
798+
parse_unexpected_expr_in_pat_inline_const_sugg = wrap the expression in a inline const (requires `{"#"}![feature(inline_const_pat)]`)
799+
800+
parse_unexpected_expr_in_pat_remove_let_sugg =
801+
remove the `let` if you meant to {$has_initializer ->
802+
[true] do an assignment
803+
*[false] evaluate an expression
804+
}
805+
806+
parse_unexpected_expr_in_pat_update_guard_sugg = check the value in the arm guard
807+
794808
parse_unexpected_if_with_if = unexpected `if` in the condition expression
795809
.suggestion = remove the `if`
796810

compiler/rustc_parse/src/errors.rs

+86
Original file line numberDiff line numberDiff line change
@@ -2603,6 +2603,92 @@ pub(crate) struct UnexpectedExpressionInPattern {
26032603
pub is_bound: bool,
26042604
}
26052605

2606+
#[derive(Subdiagnostic)]
2607+
pub(crate) enum UnexpectedExpressionInPatternSugg {
2608+
#[multipart_suggestion(
2609+
parse_unexpected_expr_in_pat_remove_let_sugg,
2610+
applicability = "maybe-incorrect",
2611+
style = "verbose"
2612+
)]
2613+
RemoveLet {
2614+
/// The span of the `let` keyword.
2615+
#[suggestion_part(code = "")]
2616+
let_span: Span,
2617+
/// The span of the type annotation.
2618+
#[suggestion_part(code = "")]
2619+
ty_span: Option<Span>,
2620+
/// `true` iff the `let` statement has an initializer.
2621+
has_initializer: bool,
2622+
},
2623+
2624+
#[multipart_suggestion(
2625+
parse_unexpected_expr_in_pat_create_guard_sugg,
2626+
applicability = "maybe-incorrect"
2627+
)]
2628+
CreateGuard {
2629+
/// The span of the `PatKind:Err` to be transformed into a `PatKind::Ident`.
2630+
#[suggestion_part(code = "{ident}")]
2631+
ident_span: Span,
2632+
/// The end of the match arm's pattern.
2633+
#[suggestion_part(code = " if {ident} == {expr}")]
2634+
pat_hi: Span,
2635+
/// The suggested identifier.
2636+
ident: String,
2637+
/// `ident_span`'s snippet.
2638+
expr: String,
2639+
},
2640+
2641+
#[multipart_suggestion(
2642+
parse_unexpected_expr_in_pat_update_guard_sugg,
2643+
applicability = "maybe-incorrect"
2644+
)]
2645+
UpdateGuard {
2646+
/// The span of the `PatKind:Err` to be transformed into a `PatKind::Ident`.
2647+
#[suggestion_part(code = "{ident}")]
2648+
ident_span: Span,
2649+
/// The beginning of the match arm guard's expression.
2650+
#[suggestion_part(code = "(")]
2651+
guard_lo: Span,
2652+
/// The end of the match arm guard's expression.
2653+
#[suggestion_part(code = ") && {ident} == {expr}")]
2654+
guard_hi: Span,
2655+
/// The suggested identifier.
2656+
ident: String,
2657+
/// `ident_span`'s snippet.
2658+
expr: String,
2659+
},
2660+
2661+
#[multipart_suggestion(
2662+
parse_unexpected_expr_in_pat_const_sugg,
2663+
applicability = "has-placeholders"
2664+
)]
2665+
Const {
2666+
/// The beginning of statement's line.
2667+
#[suggestion_part(code = "{indentation}const {ident}: _ = {expr};\n")]
2668+
stmt_lo: Span,
2669+
/// The span of the `PatKind:Err` to be transformed into a `PatKind::Ident`.
2670+
#[suggestion_part(code = "{ident}")]
2671+
ident_span: Span,
2672+
/// The suggested identifier.
2673+
ident: String,
2674+
/// `ident_span`'s snippet.
2675+
expr: String,
2676+
/// The statement's block's indentation.
2677+
indentation: String,
2678+
},
2679+
2680+
#[multipart_suggestion(
2681+
parse_unexpected_expr_in_pat_inline_const_sugg,
2682+
applicability = "maybe-incorrect"
2683+
)]
2684+
InlineConst {
2685+
#[suggestion_part(code = "const {{ ")]
2686+
start_span: Span,
2687+
#[suggestion_part(code = " }}")]
2688+
end_span: Span,
2689+
},
2690+
}
2691+
26062692
#[derive(Diagnostic)]
26072693
#[diag(parse_unexpected_paren_in_range_pat)]
26082694
pub(crate) struct UnexpectedParenInRangePat {

0 commit comments

Comments
 (0)