Change:
The compiler could suggest that identifier must precede the pattern in the following code: playpen link: Current error message: It could be improved as:
modify labels: A-diagnostics C-feature-request T-compiler
So what happens after is that we've parsed a and then follows which is not a valid token after a parsed . To fix this we can, after having parsed in , check if follows and then emit appropriate suggestions. We will need to use some heuristics to figure out what the user wants based on the structure of . Some of the suggestions would be and some not. cc

Discussion:
let pat = self.mk_pat(lo.to(self.prev_span), pat); let pat = self.maybe_recover_from_bad_qpath(pat, true)?; <ins> let pat = self.recover_intersection_pat(pat)?; </ins> if !allow_range_pat { self.ban_pat_range_if_ambiguous(&pat)?

Ok(pat) } <ins> /// Try to recover the more general form `intersect ::= $pat_lhs @ $pat_rhs`. /// /// Allowed binding patterns generated by `binding ::= ref? mut? $ident @ $pat_rhs` /// should already have been parsed by now  at this point, /// if the next token is `@` then we can try to parse the more general form. /// /// Consult `parse_pat_ident` for the `binding` grammar. /// /// The notion of intersection patterns are found in /// e.g. [F#][and] where they are called AND-patterns. /// /// [and]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching fn recover_intersection_pat(&mut self, lhs: P<Pat>) -> PResult<'a, P<Pat>> { if self.token.kind != token::At { // Next token is not `@` so it's not going to be an intersection pattern. return Ok(lhs); } // At this point we attempt to parse `@ $pat_rhs` and emit an error. self.bump(); // `@` let mut rhs = self.parse_pat(None)?; let sp = lhs.span.to(rhs.span); if let PatKind::Ident(_, _, ref mut sub @ None) = rhs.kind { // The user inverted the order, so help them fix that. let mut applicability = Applicability::MachineApplicable; lhs.walk(&mut |p| match p.kind { // `check_match` is unhappy if the subpattern has a binding anywhere. PatKind::Ident(..) => { applicability = Applicability::MaybeIncorrect; false // Short-circuit. }, _ => true, }); let lhs_span = lhs.span; // Move the LHS into the RHS as a subpattern. // The RHS is now the full pattern. *sub = Some(lhs); self.struct_span_err(sp, "pattern on wrong side of `@`") .span_label(lhs_span, "pattern on the left, should be on the right") .span_label(rhs.span, "binding on the right, should be on the left") .span_suggestion(sp, "switch the order", pprust::pat_to_string(&rhs), applicability) .emit(); } else { // The special case above doesn't apply so we may have e.g. `A(x) @ B(y)`. rhs.kind = PatKind::Wild; self.struct_span_err(sp, "left-hand side of `@` must be a binding") .span_label(lhs.span, "interpreted as a pattern, not a binding") .span_label(rhs.span, "also a pattern") .note("bindings are `x`, `mut x`, `ref x`, and `ref mut x`") .emit(); } rhs.span = sp; Ok(rhs) } </ins> /// Ban a range pattern if it has an ambiguous interpretation. fn ban_pat_range_if_ambiguous(&self, pat: &Pat) -> PResult<'a, ()> { match pat.kind {

} self.print_ident(ident); if let Some(ref p) = *sub { <del> self.s.word("@"); </del> <ins> self.s.space(); self.s.word_space("@"); </ins> self.print_pat(p); } }

<ins> // This tests the parser recovery in `recover_intersection_pat` // and serves as a regression test for the diagnostics issue #65400. // // The general idea is that for `$pat_lhs @ $pat_rhs` where // `$pat_lhs` is not generated by `ref? mut? $ident` we want // to suggest either switching the order or note that intersection // patterns are not allowed. fn main() { let s: Option<u8> = None; match s { Some(x) @ y => {} //~^ ERROR pattern on wrong side of `@` //~| pattern on the left, should be on the right //~| binding on the right, should be on the left //~| HELP switch the order //~| SUGGESTION y @ Some(x) _ => {} } match s { Some(x) @ Some(y) => {} //~^ ERROR left-hand side of `@` must be a binding //~| interpreted as a pattern, not a binding //~| also a pattern //~| NOTE bindings are `x`, `mut x`, `ref x`, and `ref mut x` _ => {} } match 2 { 1 ..= 5 @ e => {} //~^ ERROR pattern on wrong side of `@` //~| pattern on the left, should be on the right //~| binding on the right, should be on the left //~| HELP switch the order //~| SUGGESTION e @ 1 ..=5 _ => {} } } </ins>

<ins> error: pattern on wrong side of `@` --> $DIR/intersection-patterns.rs:13:9 | LL |         Some(x) @ y => {} |         -------^^^- |         |         | |         |         binding on the right, should be on the left |         pattern on the left, should be on the right |         help: switch the order: `y @ Some(x)` error: left-hand side of `@` must be a binding --> $DIR/intersection-patterns.rs:23:9 | LL |         Some(x) @ Some(y) => {} |         -------^^^------- |         |         | |         |         also a pattern |         interpreted as a pattern, not a binding | = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x` error: pattern on wrong side of `@` --> $DIR/intersection-patterns.rs:32:9 | LL |         1 ..= 5 @ e => {} |         -------^^^- |         |         | |         |         binding on the right, should be on the left |         pattern on the left, should be on the right |         help: switch the order: `e @ 1 ..=5` error: aborting due to 3 previous errors </ins>