From 98332c108b8074954203fa4b0c82fbab876d3059 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Sat, 20 Apr 2024 15:52:22 +0200 Subject: [PATCH] Improve handling of expr->field errors The current message for "`->` used for field access" is the following: ```rust error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `->` --> src/main.rs:2:6 | 2 | a->b; | ^^ expected one of 8 possible tokens ``` (playground link[1]) This PR tries to address this by adding a dedicated error message and recovery. The proposed error message is: ``` error: `->` used for field access or method call --> ./tiny_test.rs:2:6 | 2 | a->b; | ^^ help: try using `.` instead | = help: the `.` operator will dereference the value if needed ``` (feel free to bikeshed it as much as necessary) [1]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7f8b6f4433aa7866124123575456f54e Signed-off-by: Sasha Pourcelot --- compiler/rustc_parse/messages.ftl | 4 ++ compiler/rustc_parse/src/errors.rs | 9 ++++ compiler/rustc_parse/src/parser/expr.rs | 6 +++ tests/ui/parser/expr-rarrow-call.fixed | 33 +++++++++++++++ tests/ui/parser/expr-rarrow-call.rs | 33 +++++++++++++++ tests/ui/parser/expr-rarrow-call.stderr | 42 +++++++++++++++++++ tests/ui/parser/issues/issue-118530-ice.rs | 3 +- .../ui/parser/issues/issue-118530-ice.stderr | 14 +++++-- 8 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 tests/ui/parser/expr-rarrow-call.fixed create mode 100644 tests/ui/parser/expr-rarrow-call.rs create mode 100644 tests/ui/parser/expr-rarrow-call.stderr diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index e2436759c22c5..32a0df2f619ad 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -230,6 +230,10 @@ parse_expected_struct_field = expected one of `,`, `:`, or `{"}"}`, found `{$tok parse_expected_trait_in_trait_impl_found_type = expected a trait, found type +parse_expr_rarrow_call = `->` used for field access or method call + .suggestion = try using `.` instead + .help = the `.` operator will dereference the value if needed + parse_extern_crate_name_with_dashes = crate name using dashes are not valid in `extern crate` statements .label = dash-separated idents are not valid .suggestion = if the original crate name uses dashes you need to use underscores in the code diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index eae2d904c35e1..ca8de4240f450 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2988,3 +2988,12 @@ pub(crate) struct AsyncImpl { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(parse_expr_rarrow_call)] +#[help] +pub(crate) struct ExprRArrowCall { + #[primary_span] + #[suggestion(style = "short", applicability = "machine-applicable", code = ".")] + pub span: Span, +} diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 00947a4c5853f..8a4546107186b 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -979,6 +979,12 @@ impl<'a> Parser<'a> { // we are using noexpect here because we don't expect a `.` directly after a `return` // which could be suggested otherwise self.eat_noexpect(&token::Dot) + } else if self.token.kind == TokenKind::RArrow && self.may_recover() { + // Recovery for `expr->suffix`. + self.bump(); + let span = self.prev_token.span; + self.dcx().emit_err(errors::ExprRArrowCall { span }); + true } else { self.eat(&token::Dot) }; diff --git a/tests/ui/parser/expr-rarrow-call.fixed b/tests/ui/parser/expr-rarrow-call.fixed new file mode 100644 index 0000000000000..9a05e20092dd8 --- /dev/null +++ b/tests/ui/parser/expr-rarrow-call.fixed @@ -0,0 +1,33 @@ +//@ run-rustfix +#![allow( + dead_code, + unused_must_use +)] + +struct Named { + foo: usize +} + +struct Unnamed(usize); + +fn named_struct_field_access(named: &Named) { + named.foo; //~ ERROR `->` used for field access or method call +} + +fn unnamed_struct_field_access(unnamed: &Unnamed) { + unnamed.0; //~ ERROR `->` used for field access or method call +} + +fn tuple_field_access(t: &(u8, u8)) { + t.0; //~ ERROR `->` used for field access or method call + t.1; //~ ERROR `->` used for field access or method call +} + +#[derive(Clone)] +struct Foo; + +fn method_call(foo: &Foo) { + foo.clone(); //~ ERROR `->` used for field access or method call +} + +fn main() {} diff --git a/tests/ui/parser/expr-rarrow-call.rs b/tests/ui/parser/expr-rarrow-call.rs new file mode 100644 index 0000000000000..760b0f6f345b9 --- /dev/null +++ b/tests/ui/parser/expr-rarrow-call.rs @@ -0,0 +1,33 @@ +//@ run-rustfix +#![allow( + dead_code, + unused_must_use +)] + +struct Named { + foo: usize +} + +struct Unnamed(usize); + +fn named_struct_field_access(named: &Named) { + named->foo; //~ ERROR `->` used for field access or method call +} + +fn unnamed_struct_field_access(unnamed: &Unnamed) { + unnamed->0; //~ ERROR `->` used for field access or method call +} + +fn tuple_field_access(t: &(u8, u8)) { + t->0; //~ ERROR `->` used for field access or method call + t->1; //~ ERROR `->` used for field access or method call +} + +#[derive(Clone)] +struct Foo; + +fn method_call(foo: &Foo) { + foo->clone(); //~ ERROR `->` used for field access or method call +} + +fn main() {} diff --git a/tests/ui/parser/expr-rarrow-call.stderr b/tests/ui/parser/expr-rarrow-call.stderr new file mode 100644 index 0000000000000..90082f98cb5f8 --- /dev/null +++ b/tests/ui/parser/expr-rarrow-call.stderr @@ -0,0 +1,42 @@ +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:14:10 + | +LL | named->foo; + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:18:12 + | +LL | unnamed->0; + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:22:6 + | +LL | t->0; + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:23:6 + | +LL | t->1; + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:30:8 + | +LL | foo->clone(); + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: aborting due to 5 previous errors + diff --git a/tests/ui/parser/issues/issue-118530-ice.rs b/tests/ui/parser/issues/issue-118530-ice.rs index e758e5af4d9ec..cf14eebec2b76 100644 --- a/tests/ui/parser/issues/issue-118530-ice.rs +++ b/tests/ui/parser/issues/issue-118530-ice.rs @@ -3,8 +3,9 @@ fn bar() -> String { [1, 2, 3].iter() //~ ERROR expected `;`, found `#` #[feature] attr::fn bar() -> String { //~ ERROR expected identifier, found keyword `fn` - //~^ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `->` + //~^ ERROR expected one of `(`, `.`, `::`, `;`, `?`, `}`, or an operator, found `{` //~| ERROR expected `;`, found `bar` + //~| ERROR `->` used for field access or method call #[attr] [1, 2, 3].iter().map().collect::() #[attr] diff --git a/tests/ui/parser/issues/issue-118530-ice.stderr b/tests/ui/parser/issues/issue-118530-ice.stderr index ef573fb7ba3de..75c6a40c74450 100644 --- a/tests/ui/parser/issues/issue-118530-ice.stderr +++ b/tests/ui/parser/issues/issue-118530-ice.stderr @@ -33,11 +33,19 @@ LL | attr::fn bar() -> String { | | | help: add `;` here -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `->` +error: `->` used for field access or method call --> $DIR/issue-118530-ice.rs:5:20 | LL | attr::fn bar() -> String { - | ^^ expected one of `.`, `;`, `?`, `}`, or an operator + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: expected one of `(`, `.`, `::`, `;`, `?`, `}`, or an operator, found `{` + --> $DIR/issue-118530-ice.rs:5:30 + | +LL | attr::fn bar() -> String { + | ^ expected one of 7 possible tokens -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors