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 <sasha.pourcelot@protonmail.com>
This commit is contained in:
Sasha Pourcelot 2024-04-20 15:52:22 +02:00
parent a61b14d15e
commit 98332c108b
8 changed files with 140 additions and 4 deletions

View file

@ -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

View file

@ -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,
}

View file

@ -979,6 +979,12 @@ fn parse_expr_dot_or_call_with_(&mut self, mut e: P<Expr>, lo: Span) -> PResult<
// 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)
};

View file

@ -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() {}

View file

@ -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() {}

View file

@ -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

View file

@ -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::<String>()
#[attr]

View file

@ -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: aborting due to 4 previous errors
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 5 previous errors