Detect missing .
in method chain in let bindings and statements
On parse errors where an ident is found where one wasn't expected, see if the next elements might have been meant as method call or field access. ``` error: expected one of `.`, `;`, `?`, `else`, or an operator, found `map` --> $DIR/missing-dot-on-statement-expression.rs:7:29 | LL | let _ = [1, 2, 3].iter()map(|x| x); | ^^^ expected one of `.`, `;`, `?`, `else`, or an operator | help: you might have meant to write a method call | LL | let _ = [1, 2, 3].iter().map(|x| x); | + ```
This commit is contained in:
parent
9e136a30a9
commit
1ce0fa98c7
7 changed files with 165 additions and 2 deletions
|
@ -745,6 +745,42 @@ impl<'a> Parser<'a> {
|
|||
Ok(self.mk_block(stmts, s, lo.to(self.prev_token.span)))
|
||||
}
|
||||
|
||||
fn recover_missing_dot(&mut self, err: &mut Diag<'_>) {
|
||||
if !self.token.is_ident() {
|
||||
return;
|
||||
}
|
||||
if self.token.is_reserved_ident() && !self.token.is_ident_named(kw::Await) {
|
||||
return;
|
||||
}
|
||||
if self.prev_token.is_reserved_ident() && self.prev_token.is_ident_named(kw::Await) {
|
||||
// Likely `foo.await bar`
|
||||
} else if !self.prev_token.is_reserved_ident() && self.prev_token.is_ident() {
|
||||
// Likely `foo bar`
|
||||
} else if self.prev_token.kind == token::Question {
|
||||
// `foo? bar`
|
||||
} else if self.prev_token.kind == token::CloseDelim(Delimiter::Parenthesis) {
|
||||
// `foo() bar`
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if self.look_ahead(1, |t| [token::Semi, token::Question, token::Dot].contains(&t.kind)) {
|
||||
err.span_suggestion_verbose(
|
||||
self.prev_token.span.between(self.token.span),
|
||||
"you might have meant to write a field access",
|
||||
".".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
if self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Parenthesis)) {
|
||||
err.span_suggestion_verbose(
|
||||
self.prev_token.span.between(self.token.span),
|
||||
"you might have meant to write a method call",
|
||||
".".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses a statement, including the trailing semicolon.
|
||||
pub fn parse_full_stmt(
|
||||
&mut self,
|
||||
|
@ -851,7 +887,8 @@ impl<'a> Parser<'a> {
|
|||
Some(if recover.no() {
|
||||
res?
|
||||
} else {
|
||||
res.unwrap_or_else(|e| {
|
||||
res.unwrap_or_else(|mut e| {
|
||||
self.recover_missing_dot(&mut e);
|
||||
let guar = e.emit();
|
||||
self.recover_stmt();
|
||||
guar
|
||||
|
@ -872,7 +909,12 @@ impl<'a> Parser<'a> {
|
|||
// We might be at the `,` in `let x = foo<bar, baz>;`. Try to recover.
|
||||
match &mut local.kind {
|
||||
LocalKind::Init(expr) | LocalKind::InitElse(expr, _) => {
|
||||
self.check_mistyped_turbofish_with_multiple_type_params(e, expr)?;
|
||||
self.check_mistyped_turbofish_with_multiple_type_params(e, expr).map_err(
|
||||
|mut e| {
|
||||
self.recover_missing_dot(&mut e);
|
||||
e
|
||||
},
|
||||
)?;
|
||||
// We found `foo<bar, baz>`, have we fully recovered?
|
||||
self.expect_semi()?;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue