From 3a4b5c5eb9d66285bef85d19bece0b3e60306183 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 29 Sep 2025 14:21:52 -0700 Subject: [PATCH 1/2] Add a note to patterns.ident.precedent This attempts to clarify the parsing ambiguity between `IdentifierPattern` and `PathPattern`. See [`PatKind::Ident`] and [`lower_pat_ident`]. Closes https://github.com/rust-lang/reference/issues/605 [`PatKind::Ident`]: https://github.com/rust-lang/rust/blob/dc2c3564d273cf8ccce32dc4f47eaa27063bceb9/compiler/rustc_ast/src/ast.rs#L862-L866 [`lower_pat_ident`]: https://github.com/rust-lang/rust/blob/dc2c3564d273cf8ccce32dc4f47eaa27063bceb9/compiler/rustc_ast_lowering/src/pat.rs#L278-L333 --- src/patterns.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/patterns.md b/src/patterns.md index 3a27197f0b..5b617291eb 100644 --- a/src/patterns.md +++ b/src/patterns.md @@ -257,6 +257,28 @@ Its objective is exclusively to make the matched binding a reference, instead of r[patterns.ident.precedent] [Path patterns](#path-patterns) take precedence over identifier patterns. +> [!NOTE] +> When a pattern is a single-segment identifier, the grammar is ambiguous whether it means an [IdentifierPattern] or a [PathPattern]. This ambiguity can only be resolved after [name resolution]. In the following example, the pattern is disambiguated to mean a PathPattern to a constant: +> +> ```rust +> const EXPECTED_VALUE: i32 = 42; +> +> fn check_value(x: i32) -> bool { +> match x { +> EXPECTED_VALUE => true, // PathPattern - matches the constant 42 +> _ => false, +> } +> } +> +> fn main() { +> // If EXPECTED_VALUE were treated as an IdentifierPattern, it would bind +> // any value to a new variable, making this function always return true +> // regardless of the input. +> assert_eq!(check_value(42), true); // correct behavior +> assert_eq!(check_value(100), false); // would be true if misinterpreted +> } +> ``` + r[patterns.ident.constraint] It is an error if `ref` or `ref mut` is specified and the identifier shadows a constant. @@ -1085,6 +1107,7 @@ For example, `x @ A(..) | B(..)` will result in an error that `x` is not bound i [enums]: items/enumerations.md [literals]: expressions/literal-expr.md [literal expression]: expressions/literal-expr.md +[name resolution]: names/name-resolution.md [negating]: expressions/operator-expr.md#negation-operators [path]: expressions/path-expr.md [pattern matching on unions]: items/unions.md#pattern-matching-on-unions From 2a45d5de4d714dcebbba56f36d2d97091703a783 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 7 Oct 2025 22:30:54 +0000 Subject: [PATCH 2/2] Revise note about `{Path,Identifier}Pattern` parsing Let's extend the example to demonstrate, comparatively, what is parsed as an `IdentifierPattern`. Even though this is the common case, showing this might be helpful to people less familiar with the grammar. Let's remove `main`, as that's not needed here. And, in the code, let's highlight specifically what we're commenting on by commenting below the construct. --- src/patterns.md | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/patterns.md b/src/patterns.md index 5b617291eb..f26cbad80f 100644 --- a/src/patterns.md +++ b/src/patterns.md @@ -258,25 +258,28 @@ r[patterns.ident.precedent] [Path patterns](#path-patterns) take precedence over identifier patterns. > [!NOTE] -> When a pattern is a single-segment identifier, the grammar is ambiguous whether it means an [IdentifierPattern] or a [PathPattern]. This ambiguity can only be resolved after [name resolution]. In the following example, the pattern is disambiguated to mean a PathPattern to a constant: +> When a pattern is a single-segment identifier, the grammar is ambiguous whether it means an [IdentifierPattern] or a [PathPattern]. This ambiguity can only be resolved after [name resolution]. > > ```rust -> const EXPECTED_VALUE: i32 = 42; +> const EXPECTED_VALUE: u8 = 42; +> // ^^^^^^^^^^^^^^ That this constant is in scope affects how the +> // patterns below are treated. > -> fn check_value(x: i32) -> bool { +> fn check_value(x: u8) -> Result { > match x { -> EXPECTED_VALUE => true, // PathPattern - matches the constant 42 -> _ => false, +> EXPECTED_VALUE => Ok(x), +> // ^^^^^^^^^^^^^^ Parsed as a `PathPattern` that resolves to +> // the constant `42`. +> other_value => Err(x), +> // ^^^^^^^^^^^ Parsed as an `IdentifierPattern`. > } > } > -> fn main() { -> // If EXPECTED_VALUE were treated as an IdentifierPattern, it would bind -> // any value to a new variable, making this function always return true -> // regardless of the input. -> assert_eq!(check_value(42), true); // correct behavior -> assert_eq!(check_value(100), false); // would be true if misinterpreted -> } +> // If `EXPECTED_VALUE` were treated as an `IdentifierPattern` above, +> // that pattern would always match, making the function always return +> // `Ok(_) regardless of the input. +> assert_eq!(check_value(42), Ok(42)); +> assert_eq!(check_value(43), Err(43)); > ``` r[patterns.ident.constraint]