Change:
expected.sort_by_cached_key(|x| x.to_string()); expected.dedup(); <ins> let sm = self.sess.source_map(); let msg = format!("expected `;`, found {}", super::token_descr(&self.token)); let appl = Applicability::MachineApplicable; if expected.contains(&TokenType::Token(token::Semi)) { if self.token.span == DUMMY_SP || self.prev_token.span == DUMMY_SP { // Likely inside a macro, can't provide meaningful suggestions. } else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) { // The current token is in the same line as the prior token, not recoverable. } else if [token::Comma, token::Colon].contains(&self.token.kind) && self.prev_token.kind == token::CloseDelim(token::Paren) { // Likely typo: The current token is on a new line and is expected to be // `.`, `;`, `?`, or an operator after a close delimiter token. // // let a = std::process::Command::new("echo") //         .arg("1") //         ,arg("2") //         ^ // https://github.com/rust-lang/rust/issues/72253 } else if self.look_ahead(1, |t| { t == &token::CloseDelim(token::Brace) || t.can_begin_expr() && t.kind != token::Colon }) && [token::Comma, token::Colon].contains(&self.token.kind) { // Likely typo: `,` → `;` or `:` → `;`. This is triggered if the current token is // either `,` or `:`, and the next token could either start a new statement or is a // block close. For example: // //   let x = 32: //   let y = 42; self.bump(); let sp = self.prev_token.span; self.struct_span_err(sp, &msg) .span_suggestion_short(sp, "change this to `;`", ";".to_string(), appl) .emit(); return Ok(false); } else if self.look_ahead(0, |t| { t == &token::CloseDelim(token::Brace) || ( t.can_begin_expr() && t != &token::Semi && t != &token::Pound // Avoid triggering with too many trailing `#` in raw string. ) }) { // Missing semicolon typo. This is triggered if the next token could either start a // new statement or is a block close. For example: // //   let x = 32 //   let y = 42; let sp = self.prev_token.span.shrink_to_hi(); self.struct_span_err(sp, &msg) .span_label(self.token.span, "unexpected token") .span_suggestion_short(sp, "add `;` here", ";".to_string(), appl) .emit(); return Ok(false); } } </ins> let expect = tokens_to_string(&expected[..]); let actual = super::token_descr(&self.token); let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {

Discussion:
: The current output is: We should detect cases where a semicolon would be appropriate (probe that the current token and maybe limited lookahead confirm that what comes next could be a valid statement on its own) and suggest a semicolon. . We might want to silence one or the other depending on whether the current token might be starting a statement or an item ( vs , etc.). <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
claim
Sorry, I don't have much time these days. release-assignment
Just a guess: could this be addressed with another block, as in
I think we would need to answer this question: why is the logic here not handling the cases we want to handle?
This seems to be on track given the clue "probe that the current token and maybe limited lookahead confirm that what comes next could be a valid statement on its own"...
claim
release-assignment
That is a great question: as the code is written it looks like it should work. I don't know why it isn't triggering :( It might be that isn't being called in these case. It might be a good idea to uplift most of this method into
I'd like to give this a try. claim