Repository navigation
Further improve diagnostics for expressions in pattern position #121697
Description
Activity
- addedA-diagnosticsArea: Messages for errors, warnings, and lintsArea: Messages for errors, warnings, and lintsA-parserArea: The lexing & parsing of Rust source code to an ASTArea: The lexing & parsing of Rust source code to an ASTT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.A-patternsRelating to patterns and pattern matchingRelating to patterns and pattern matching
on Feb 27, 2024 cc @ShE3py, @WaffleLapkin
- changed the title
[-]Further improve diagnostics for expressions in patterns[/-][+]Further improve diagnostics for expressions in pattern position[/+]on Feb 27, 2024 - addedD-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.Diagnostics: Confusing error or lint; hard to understand for new users.D-terseDiagnostics: An error or lint that doesn't give enough information about the problem at hand.Diagnostics: An error or lint that doesn't give enough information about the problem at hand.
on Feb 27, 2024 I know that this is quite a wall of text and I don't expect anyone to read it. I've tagged you, ShE3py, since you might be interested in working on some of the things I listed here. Otherwise this issue just serves as a public TODO list for me.
Okay, I've somehow resurrected.
1. ii. Then, we should in my opinion check the
Spanto make sure that there's no whitespace/comment before & after the.to avoid overzealously emitting this diagnostic when the user accidentally typoed a comma as a dot (as in(x. y)←(x, y)) which isn't too farfetched given the keys are right next to each other on most keyboardsIt might be worth to emit both diagnostics (e.g. “unexpected field access // try introducing a
const VAL: _ = x. y// you may have meant to use a comma there”).1. iii. The following is a bit opinionated: I think we should remove the capitalization check (at the moment, we don't consider x.Foo() to be a method call).
Likewise. Especially since some scripts e.g. Arabic doesn't have cases (the check should've been something like
!c.is_uppercase()).1. iv. See
parse_expr_tuple_field_access_floatfor prior art.Note to self: this was inlined into
parse_dot_suffix_exprin #122858.
Permalink to that PR's parent:rust/compiler/rustc_parse/src/parser/expr.rs
Lines 1122 to 1155 in 0824b30
fn parse_expr_tuple_field_access_float( &mut self, lo: Span, base: P<Expr>, float: Symbol, suffix: Option<Symbol>, ) -> P<Expr> { match self.break_up_float(float, self.token.span) { // 1e2 DestructuredFloat::Single(sym, _sp) => { self.parse_expr_tuple_field_access(lo, base, sym, suffix, None) } // 1. DestructuredFloat::TrailingDot(sym, ident_span, dot_span) => { assert!(suffix.is_none()); self.token = Token::new(token::Ident(sym, IdentIsRaw::No), ident_span); let next_token = (Token::new(token::Dot, dot_span), self.token_spacing); self.parse_expr_tuple_field_access(lo, base, sym, None, Some(next_token)) } // 1.2 | 1.2e3 DestructuredFloat::MiddleDot(symbol1, ident1_span, dot_span, symbol2, ident2_span) => { self.token = Token::new(token::Ident(symbol1, IdentIsRaw::No), ident1_span); // This needs to be `Spacing::Alone` to prevent regressions. // See issue #76399 and PR #76285 for more details let next_token1 = (Token::new(token::Dot, dot_span), Spacing::Alone); let base1 = self.parse_expr_tuple_field_access(lo, base, symbol1, None, Some(next_token1)); let next_token2 = Token::new(token::Ident(symbol2, IdentIsRaw::No), ident2_span); self.bump_with((next_token2, self.token_spacing)); // `.` self.parse_expr_tuple_field_access(lo, base1, symbol2, suffix, None) } DestructuredFloat::Error => base, } } I know that this is quite a wall of text and I don't expect anyone to read it. I've tagged you, ShE3py, since you might be interested in working on some of the things I listed here. Otherwise this issue just serves as a public TODO list for me.
I don't mind reading, and I often find myself writing walls of text, albeit in French, and my English isn't so good as to write pavés in it while retaining the same meaning.
@rustbot claim
Reacted by León Orell Valerian Liehr
I've had this on my TODO list for a while but never had the time to write a PR for it. Therefore I'm just going to open an issue for it instead.
Since PR #118625 we try to reparse something in pattern position as an expression under certain conditions and provide a smarter diagnostic of the form “expected a pattern, found an expression // arbitrary expressions are not allowed in patterns” which is already amazing.
However, the current heuristic has a few limitations I'd like to see addressed which should be relatively simple to implement:
$literal.$identand so forth) but only things that look like method calls (e.g.,0.f()). I argue we should also detect expressions likex.fands.0. This would've prevented #104996 from getting opened! (addressed in #123877).-“herald” check.Spanto make sure that there's no whitespace/comment before & after the.to avoid overzealously emitting this diagnostic when the user accidentally typoed a comma as a dot (as in(x. y)←(x, y)) which isn't too farfetched given the keys are right next to each other on most keyboards (just need to checksp0.hi == sp1.lo). Of course, this would rule out multi-line method / field chains but that should be rare. We could (as a follow-up) check if the would-be expression is “appropriately” indented (by utilizingSourceMapmethods) to address that, too. (NOTE: this isn't implemented yet, unclear if we actually want this)x.Foo()to be a method call). If you disagree, we should at least also consider_to be a valid start of a field or method name (x._foo()doesn't get recognized at the time of writing).x.0.1without accidentally flaggingx.0e4as an expression (x.0.1gets lexed as [Ident, Dot, FloatLit]). Seeparse_expr_tuple_field_access_floatfor prior art.asto be a “herald” next to.to recover0 as usizeetc. in pattern position (addressed in #123877).f().g()andetc. meaning more method calls / field accesses where the “basis” is a more complex expression. Rephrased: Recognize more “(0).f()$expr.$ident” over just “$lit_or_ident.$ident” (the latter is the status quo, roughly, if I'm not mistaken).(0).f()was addressed in #123877.constand refer to that” (addressed in #123877).const {}block (featureinline_const_pat). We could provide the suggestion ifself.sess.unstable_features.is_nightly_build()holds but I don't know if others like the idea of that. Note that we cannot check if featureinline_const_patis enabled from inside the parserand diagnostic stashing/stealing doesn't help here either since we want to “stash” a subdiagnostic (a structured suggestion)not true actually, should be possible to impl (addressed in #123877.