Change:
match stmt.kind { // Expression without semicolon. StmtKind::Expr(ref mut expr) <del> if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => { </del> <ins> if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => { </ins> // Just check for errors and recover; do not eat semicolon yet. <del> if let Err(mut e) = self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]) { if let TokenKind::DocComment(..) = self.token.kind { if let Ok(snippet) = self.span_to_snippet(self.token.span) { let sp = self.token.span; let marker = &snippet[..3]; let (comment_marker, doc_comment_marker) = marker.split_at(2); e.span_suggestion( sp.with_hi(sp.lo() + BytePos(marker.len() as u32)), &format!( "add a space before `{}` to use a regular comment", doc_comment_marker, ), format!("{} {}", comment_marker, doc_comment_marker), Applicability::MaybeIncorrect, ); </del> <ins> // `expect_one_of` returns PResult<'a, bool /* recovered */> let replace_with_err = match self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]) { // Recover from parser, skip type error to avoid extra errors. Ok(true) => true, Err(mut e) => { if let TokenKind::DocComment(..) = self.token.kind && let Ok(snippet) = self.span_to_snippet(self.token.span) { let sp = self.token.span; let marker = &snippet[..3]; let (comment_marker, doc_comment_marker) = marker.split_at(2); e.span_suggestion( sp.with_hi(sp.lo() + BytePos(marker.len() as u32)), &format!( "add a space before `{}` to use a regular comment", doc_comment_marker, ), format!("{} {}", comment_marker, doc_comment_marker), Applicability::MaybeIncorrect, ); </ins> } <del> } if let Err(mut e) = self.check_mistyped_turbofish_with_multiple_type_params(e, expr) { if recover.no() { return Err(e); </del> <ins> if let Err(mut e) = self.check_mistyped_turbofish_with_multiple_type_params(e, expr) { if recover.no() { return Err(e); } e.emit(); self.recover_stmt(); </ins> } <del> e.emit(); self.recover_stmt(); </del> <ins> true </ins> } <del> // Don't complain about type errors in body tail after parse error (#57383). </del> <ins> _ => false }; if replace_with_err { // We already emitted an error, so don't emit another type error </ins> let sp = expr.span.to(self.prev_token.span); *expr = self.mk_expr_err(sp); }

Discussion:
Given the following code (): The current output is: What is this second error trying to tell me? What did it expect to be unit type and why? Does it make sense for this error to be emitted despite the first error correctly identifying my problem? <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
It's trying to tell you nothing in particular. This is a bug, due to the fact that we eat the token and replace it with , so the "fixed" body ends up being:
That theory doesn't seem right to me, for two reasons: I would expect eating the to result in a type error like "expected because of return type", but the actual error involves integer and unit. Repeating the missing-semi error results in repeating the type error as well, even though it's all within one function. : gives two missing-semi errors and two type errors:
The error is reported at this point Then it's considered as recovered, and the are reported at type anlysising phase. Should we treat it as unrecovered, or make the dummy so that type anlysising won't report error messages?
claim
please first understand what the AST doing on the semicolon recovery path, then once that's done, you can probably try to make it recover like: properly so it type-checks correctly.