Change:
The idea of shortening to has been discussed many times before, and the general consensus always ends up being that it is not a good idea. I would like to propose something a bit different, so please hear me out. I propose that instead of aliasing to , we instead just make expand into when in the context of a variable declaration. For example: This solves the problems (readability, more concise) that people have with , whilst not causing the issues that people have (pattern matching and consistancy). The most common issue people have with aliasing to is that it doesn't fit well with patterns, like . However, gets rid of this problem, because you wouldn't write if you were trying to pattern match, so why would someone want to write ? You wouldn't do that, and it wouldn't compile. This would be optional, of course. would still work fine, and people would just have to option of removing the to let it be implied. There are a lot of other abbreviations used in rust (, , ) that all serve the purpose of writing less. It just doesn't feel right that one of the most commonly used keywords is so long. :heart::crab: <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
Rust wants to make to make you think when you try and use mutation, even if only a little bit, because mutation can be difficult to reason about. Shortening to doesn't fit this philosophy. Also, this makes mutation just as easy as no mutation. This will lead people to choose mutation because it will give them less compiler errors in the short term, and in doing so open themselves up to some weird bugs that could have been prevented with the syntactic salt that is . tldr: wasn't rejected because of the name , but because it allowed easy mutation, which runs counter to Rust's philosophy.
I politely disagree. In fact, it is actually the other way around. Using unnecessarily will cause compiler warnings, discouraging the use of unneeded mutability. The compiler doesn't warn when the use of is actually needed.
The fact that people will choose in the face of compiler warnings has been shown in practice, across many projects. Also, the problem isn't that people may choose to put just for the heck of it, but that they will unintentionally mutate something that was supposed to be immutable. And because it is being mutated, there is no warning, and they used because it is their default, it is their default because it gets rid of compiler errors that say they were trying to mutate things that are immutable even though they weren't supposed to mutate them in the first place. They will use because it is just as easy as making it immutable. So the problem is a bit more subtle than you seem to think.
Incorrect. Extreme brevity harms readability. See Perl. lol Readers would ignore the vs distinction far more often that vs , partially due to length difference, but works even better than say . It's true boilerplate often harms readability, but boilerplate requires some complexity be repeated, not merely the in . It harms readability even further if also works for , especially when you consider code readers need not actually know Rust. Rust syntax was designed largely to reduce cognitive load, not to reduce typing. We use , , and , not any shorter alternatives. And delegation RFCs have kinda given up the short syntaxes. I think Rust's omission of is now considered a mistake, but presumably helps C programmers. Rust has short keywords only really for fundamental "items" used repeatedly by basically every module. It's similar cognitive load if you write , , or , but actually just writing the shorter bare increases cognitive load. I think invokes the minor linguistic subtlety that variable means mutable binding, while acts like a common term for binding, which makes very slightly clearer.
The statement would be orthogonal to the current language in some sense though. is not a special syntax, but is composed of statement + pattern. It is in line with other places expects a pattern, where you can write , , or .
It seems unlikely to me that we would support as a short-hand. I'm personally opposed to it both because it adds unnecessary compiler complexity, stylistic schisms, and for the reasons outlined by However, I've taken the liberty of reusing this issue towards improved diagnostics: The idea here is to check . The idea here is to check: The relevant code is here: cc
claim
Error: Parsing assign command in failed: claim :)... Please let know if you're having trouble with this bot.
Although I would also guess that the initial idea is very unlikely to end up accepted, it feels premature to unilaterally hijack the thread in your very first comment and make it have a different (and in a way opposite) purpose. Teams of the Rust project are designed to make decisions collectively. Improving diagnostics sounds good, but issue numbers are cheap.
Implementing something as a diagnostic actually brings you closer to a working implementation -- I think more proposals should start out as diagnostics. I will not bother the other language team members with not-fully-formed proposals that we will not accept in either case. I converted the issue into the most actionable and productive thing it could be. The place for ephemeral discussions is either on Discord or on internals. If you want to discuss this further, I'm available at Discord (but will not respond to it further here). wasting everyone's time with things that will go nowhere (because it won't be accepted and because it is not important enough to be raised at the team) is not.
IMHO, the original thing this issue was opened for should be an RFC, not an issue. I'd have closed this, pointed the OP to the RFCs repo, and opened a new issue for the diagnostic issue.
This issue was literally in the RFCs repo initially, transferred it from there.
Language bashing is not welcome here
Wait, so should I unassign here, and assign to the new issue?
Nah, just use this one.
Yeah, thats fine. You can just change this issue to be for diagnostics instead.
I'm sorry, I've been pretty busy with coursework, and I'm still fighting my Python installation to even build the compiler, let alone make progress on this. Sorry :(
I'll assign this to myself to work on when I have time. If you want to work on it however, feel free to work-steal it from me!
I would like to help with this
Sorry; should have updated this issue...! There's a PR at the moment. Feel free to leave suggestions on it if you like. :)

Discussion:
}; let last_type_ascription_set = self.last_type_ascription.is_some(); <del> match (self.expr_is_complete(&lhs), AssocOp::from_token(&self.token)) { (true, None) => { self.last_type_ascription = None; // Semi-statement forms are odd. See https://github.com/rust-lang/rust/issues/29071 return Ok(lhs); } (false, _) => {} // continue parsing the expression // An exhaustive check is done in the following block, but these are checked first // because they *are* ambiguous but also reasonable looking incorrect syntax, so we // want to keep their span info to improve diagnostics in these cases in a later stage. (true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3` (true, Some(AssocOp::Subtract)) | // `{ 42 } -5` (true, Some(AssocOp::LAnd)) | // `{ 42 } &&x` (#61475) (true, Some(AssocOp::Add)) // `{ 42 } + 42 // If the next token is a keyword, then the tokens above *are* unambiguously incorrect: // `if x { a } else { b } && if y { c } else { d }` if !self.look_ahead(1, |t| t.is_reserved_ident()) => { self.last_type_ascription = None; // These cases are ambiguous and can't be identified in the parser alone let sp = self.sess.source_map().start_point(self.token.span); self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span); return Ok(lhs); } (true, Some(ref op)) if !op.can_continue_expr_unambiguously() => { self.last_type_ascription = None; return Ok(lhs); } (true, Some(_)) => { // We've found an expression that would be parsed as a statement, but the next // token implies this should be parsed as an expression. // For example: `if let Some(x) = x { x } else { 0 } / 2` let mut err = self.struct_span_err(self.token.span, &format!( "expected expression, found `{}`", pprust::token_to_string(&self.token), )); err.span_label(self.token.span, "expected expression"); self.sess.expr_parentheses_needed( &mut err, lhs.span, Some(pprust::expr_to_string(&lhs), )); err.emit(); } </del> <ins> if !self.should_continue_as_assoc_expr(&lhs) { self.last_type_ascription = None; return Ok(lhs); </ins> } <del> self.expected_tokens.push(TokenType::Operator); while let Some(op) = AssocOp::from_token(&self.token) { </del> <ins> self.expected_tokens.push(TokenType::Operator); while let Some(op) = self.check_assoc_op() { </ins> // Adjust the span for interpolated LHS to point to the `$lhs` token and not to what // it refers to. Interpolated identifiers are unwrapped early and never show up here // as `PrevTokenKind::Interpolated` so if LHS is a single identifier we always process

Ok(lhs) } <ins> fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool { match (self.expr_is_complete(lhs), self.check_assoc_op()) { // Semi-statement forms are odd: // See https://github.com/rust-lang/rust/issues/29071 (true, None) => false, (false, _) => true, // Continue parsing the expression. // An exhaustive check is done in the following block, but these are checked first // because they *are* ambiguous but also reasonable looking incorrect syntax, so we // want to keep their span info to improve diagnostics in these cases in a later stage. (true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3` (true, Some(AssocOp::Subtract)) | // `{ 42 } -5` (true, Some(AssocOp::LAnd)) | // `{ 42 } &&x` (#61475) (true, Some(AssocOp::Add)) // `{ 42 } + 42 // If the next token is a keyword, then the tokens above *are* unambiguously incorrect: // `if x { a } else { b } && if y { c } else { d }` if !self.look_ahead(1, |t| t.is_reserved_ident()) => { // These cases are ambiguous and can't be identified in the parser alone. let sp = self.sess.source_map().start_point(self.token.span); self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span); false } (true, Some(ref op)) if !op.can_continue_expr_unambiguously() => false, (true, Some(_)) => { self.error_found_expr_would_be_stmt(lhs); true } } } /// We've found an expression that would be parsed as a statement, /// but the next token implies this should be parsed as an expression. /// For example: `if let Some(x) = x { x } else { 0 } / 2`. fn error_found_expr_would_be_stmt(&self, lhs: &Expr) { let mut err = self.struct_span_err(self.token.span, &format!( "expected expression, found `{}`", pprust::token_to_string(&self.token), )); err.span_label(self.token.span, "expected expression"); self.sess.expr_parentheses_needed(&mut err, lhs.span, Some(pprust::expr_to_string(&lhs))); err.emit(); } /// Possibly translate the current token to an associative operator. /// The method does not advance the current token. /// /// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively. fn check_assoc_op(&self) -> Option<AssocOp> { AssocOp::from_token(&self.token) } </ins> /// Checks if this expression is a successfully parsed statement. fn expr_is_complete(&self, e: &Expr) -> bool { self.restrictions.contains(Restrictions::STMT_EXPR) &&

/// Parses a statement. This stops just before trailing semicolons on everything but items. /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed. pub fn parse_stmt(&mut self) -> PResult<'a, Option<Stmt>> { <del> Ok(self.parse_stmt_(true)) } fn parse_stmt_(&mut self, macro_legacy_warnings: bool) -> Option<Stmt> { self.parse_stmt_without_recovery(macro_legacy_warnings).unwrap_or_else(|mut e| { </del> <ins> Ok(self.parse_stmt_without_recovery(true).unwrap_or_else(|mut e| { </ins> e.emit(); self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); None <del> }) </del> <ins> })) </ins> } fn parse_stmt_without_recovery(

let attrs = self.parse_outer_attributes()?; let lo = self.token.span; <del> Ok(Some(if self.eat_keyword(kw::Let) { Stmt { id: DUMMY_NODE_ID, kind: StmtKind::Local(self.parse_local(attrs.into())?), span: lo.to(self.prev_span), } } else if let Some(macro_def) = self.eat_macro_def( &attrs, &respan(lo, VisibilityKind::Inherited), lo, )? { Stmt { id: DUMMY_NODE_ID, kind: StmtKind::Item(macro_def), span: lo.to(self.prev_span), } </del> <ins> if self.eat_keyword(kw::Let) { let local = self.parse_local(attrs.into())?; return Ok(Some(self.mk_stmt(lo.to(self.prev_span), StmtKind::Local(local)))); } let mac_vis = respan(lo, VisibilityKind::Inherited); if let Some(macro_def) = self.eat_macro_def(&attrs, &mac_vis, lo)? { return Ok(Some(self.mk_stmt(lo.to(self.prev_span), StmtKind::Item(macro_def)))); } </ins> // Starts like a simple path, being careful to avoid contextual keywords // such as a union items, item with `crate` visibility or auto trait items. // Our goal here is to parse an arbitrary path `a::b::c` but not something that starts // like a path (1 token), but it fact not a path. <del> // `union::b::c` - path, `union U { ... }` - not a path. // `crate::b::c` - path, `crate struct S;` - not a path. } else if self.token.is_path_start() && !self.token.is_qpath_start() && !self.is_union_item() && !self.is_crate_vis() && !self.is_auto_trait_item() && !self.is_async_fn() { </del> <ins> if self.token.is_path_start() && !self.token.is_qpath_start() && !self.is_union_item() // `union::b::c` - path, `union U { ... }` - not a path. && !self.is_crate_vis() // `crate::b::c` - path, `crate struct S;` - not a path. && !self.is_auto_trait_item() && !self.is_async_fn() { </ins> let path = self.parse_path(PathStyle::Expr)?; <del> if !self.eat(&token::Not) { let expr = if self.check(&token::OpenDelim(token::Brace)) { self.parse_struct_expr(lo, path, ThinVec::new())? } else { let hi = self.prev_span; self.mk_expr(lo.to(hi), ExprKind::Path(None, path), ThinVec::new()) }; let expr = self.with_res(Restrictions::STMT_EXPR, |this| { let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?; this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr)) })?; return Ok(Some(Stmt { id: DUMMY_NODE_ID, kind: StmtKind::Expr(expr), span: lo.to(self.prev_span), })); </del> <ins> if self.eat(&token::Not) { return self.parse_stmt_mac(lo, attrs.into(), path, macro_legacy_warnings); </ins> } <del> let args = self.parse_mac_args()?; let delim = args.delim(); let hi = self.prev_span; let style = if delim == token::Brace { MacStmtStyle::Braces </del> <ins> let expr = if self.check(&token::OpenDelim(token::Brace)) { self.parse_struct_expr(lo, path, ThinVec::new())? </ins> } else { <del> MacStmtStyle::NoBraces </del> <ins> let hi = self.prev_span; self.mk_expr(lo.to(hi), ExprKind::Path(None, path), ThinVec::new()) </ins> }; <del> let mac = Mac { path, args, prior_type_ascription: self.last_type_ascription, }; let kind = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof { StmtKind::Mac(P((mac, style, attrs.into()))) } // We used to incorrectly stop parsing macro-expanded statements here. // If the next token will be an error anyway but could have parsed with the // earlier behavior, stop parsing here and emit a warning to avoid breakage. else if macro_legacy_warnings && self.token.can_begin_expr() && match self.token.kind { // These can continue an expression, so we can't stop parsing and warn. token::OpenDelim(token::Paren) | token::OpenDelim(token::Bracket) | token::BinOp(token::Minus) | token::BinOp(token::Star) | token::BinOp(token::And) | token::BinOp(token::Or) | token::AndAnd | token::OrOr | token::DotDot | token::DotDotDot | token::DotDotEq => false, _ => true, } { self.warn_missing_semicolon(); StmtKind::Mac(P((mac, style, attrs.into()))) } else { let e = self.mk_expr(lo.to(hi), ExprKind::Mac(mac), ThinVec::new()); let e = self.maybe_recover_from_bad_qpath(e, true)?; let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?; let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; StmtKind::Expr(e) }; Stmt { id: DUMMY_NODE_ID, span: lo.to(hi), kind, </del> <ins> let expr = self.with_res(Restrictions::STMT_EXPR, |this| { let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?; this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr)) })?; return Ok(Some(self.mk_stmt(lo.to(self.prev_span), StmtKind::Expr(expr)))); } // FIXME: Bad copy of attrs let old_directory_ownership = mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock); let item = self.parse_item_(attrs.clone(), false, true)?; self.directory.ownership = old_directory_ownership; if let Some(item) = item { return Ok(Some(self.mk_stmt(lo.to(item.span), StmtKind::Item(item)))); } // Do not attempt to parse an expression if we're done here. if self.token == token::Semi { self.error_outer_attrs(&attrs); self.bump(); let mut last_semi = lo; while self.token == token::Semi { last_semi = self.token.span; self.bump(); </ins> } <ins> // We are encoding a string of semicolons as an an empty tuple that spans // the excess semicolons to preserve this info until the lint stage. let kind = StmtKind::Semi(self.mk_expr( lo.to(last_semi), ExprKind::Tup(Vec::new()), ThinVec::new() )); return Ok(Some(self.mk_stmt(lo.to(last_semi), kind))); } if self.token == token::CloseDelim(token::Brace) { self.error_outer_attrs(&attrs); return Ok(None); } // Remainder are line-expr stmts. let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?; Ok(Some(self.mk_stmt(lo.to(e.span), StmtKind::Expr(e)))) } /// Parses a statement macro `mac!(args)` provided a `path` representing `mac`. /// At this point, the `!` token after the path has already been eaten. fn parse_stmt_mac( &mut self, lo: Span, attrs: ThinVec<Attribute>, path: ast::Path, legacy_warnings: bool, ) -> PResult<'a, Option<Stmt>> { let args = self.parse_mac_args()?; let delim = args.delim(); let hi = self.prev_span; let style = if delim == token::Brace { MacStmtStyle::Braces </ins> } else { <del> // FIXME: Bad copy of attrs let old_directory_ownership = mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock); let item = self.parse_item_(attrs.clone(), false, true)?; self.directory.ownership = old_directory_ownership; match item { Some(i) => Stmt { id: DUMMY_NODE_ID, span: lo.to(i.span), kind: StmtKind::Item(i), }, None => { let unused_attrs = |attrs: &[Attribute], s: &mut Self| { if !attrs.is_empty() { if s.prev_token_kind == PrevTokenKind::DocComment { s.span_fatal_err(s.prev_span, Error::UselessDocComment).emit(); } else if attrs.iter().any(|a| a.style == AttrStyle::Outer) { s.span_err( s.token.span, "expected statement after outer attribute" ); } } }; // Do not attempt to parse an expression if we're done here. if self.token == token::Semi { unused_attrs(&attrs, self); self.bump(); let mut last_semi = lo; while self.token == token::Semi { last_semi = self.token.span; self.bump(); } // We are encoding a string of semicolons as an // an empty tuple that spans the excess semicolons // to preserve this info until the lint stage return Ok(Some(Stmt { id: DUMMY_NODE_ID, span: lo.to(last_semi), kind: StmtKind::Semi(self.mk_expr(lo.to(last_semi), ExprKind::Tup(Vec::new()), ThinVec::new() )), })); } </del> <ins> MacStmtStyle::NoBraces }; </ins> <del> if self.token == token::CloseDelim(token::Brace) { unused_attrs(&attrs, self); return Ok(None); } </del> <ins> let mac = Mac { path, args, prior_type_ascription: self.last_type_ascription, }; </ins> <del> // Remainder are line-expr stmts. let e = self.parse_expr_res( Restrictions::STMT_EXPR, Some(attrs.into()))?; Stmt { id: DUMMY_NODE_ID, span: lo.to(e.span), kind: StmtKind::Expr(e), } } </del> <ins> let kind = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof { StmtKind::Mac(P((mac, style, attrs.into()))) } // We used to incorrectly stop parsing macro-expanded statements here. // If the next token will be an error anyway but could have parsed with the // earlier behavior, stop parsing here and emit a warning to avoid breakage. else if legacy_warnings && self.token.can_begin_expr() && match self.token.kind { // These can continue an expression, so we can't stop parsing and warn. token::OpenDelim(token::Paren) | token::OpenDelim(token::Bracket) | token::BinOp(token::Minus) | token::BinOp(token::Star) | token::BinOp(token::And) | token::BinOp(token::Or) | token::AndAnd | token::OrOr | token::DotDot | token::DotDotDot | token::DotDotEq => false, _ => true, </ins> } <del> })) </del> <ins> { self.warn_missing_semicolon(); StmtKind::Mac(P((mac, style, attrs))) } else { // Since none of the above applied, this is an expression statement macro. let e = self.mk_expr(lo.to(hi), ExprKind::Mac(mac), ThinVec::new()); let e = self.maybe_recover_from_bad_qpath(e, true)?; let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?; let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; StmtKind::Expr(e) }; Ok(Some(self.mk_stmt(lo.to(hi), kind))) } /// Error on outer attributes in this context. /// Also error if the previous token was a doc comment. fn error_outer_attrs(&self, attrs: &[Attribute]) { if !attrs.is_empty() { if self.prev_token_kind == PrevTokenKind::DocComment { self.span_fatal_err(self.prev_span, Error::UselessDocComment).emit(); } else if attrs.iter().any(|a| a.style == AttrStyle::Outer) { self.span_err(self.token.span, "expected statement after outer attribute"); } } </ins> } /// Parses a local variable declaration.

let lo = self.token.span; if !self.eat(&token::OpenDelim(token::Brace)) { <del> let sp = self.token.span; let tok = self.this_token_descr(); let mut e = self.span_fatal(sp, &format!("expected `{{`, found {}", tok)); let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon; if self.token.is_ident_named(sym::and) { e.span_suggestion_short( self.token.span, "use `&&` instead of `and` for the boolean operator", "&&".to_string(), Applicability::MaybeIncorrect, ); } if self.token.is_ident_named(sym::or) { e.span_suggestion_short( self.token.span, "use `||` instead of `or` for the boolean operator", "||".to_string(), Applicability::MaybeIncorrect, ); } </del> <ins> return self.error_block_no_opening_brace(); } </ins> <del> // Check to see if the user has written something like // //    if (cond) //      bar; // // which is valid in other languages, but not Rust. match self.parse_stmt_without_recovery(false) { Ok(Some(stmt)) => { if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace)) || do_not_suggest_help { // If the next token is an open brace (e.g., `if a b {`), the place- // inside-a-block suggestion would be more likely wrong than right. e.span_label(sp, "expected `{`"); return Err(e); } let mut stmt_span = stmt.span; // Expand the span to include the semicolon, if it exists. if self.eat(&token::Semi) { stmt_span = stmt_span.with_hi(self.prev_span.hi()); } if let Ok(snippet) = self.span_to_snippet(stmt_span) { e.span_suggestion( stmt_span, "try placing this code inside a block", format!("{{ {} }}", snippet), // Speculative; has been misleading in the past (#46836). Applicability::MaybeIncorrect, ); } </del> <ins> self.parse_block_tail(lo, BlockCheckMode::Default) } fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> { let sp = self.token.span; let tok = self.this_token_descr(); let mut e = self.span_fatal(sp, &format!("expected `{{`, found {}", tok)); let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon; if self.token.is_ident_named(sym::and) { e.span_suggestion_short( self.token.span, "use `&&` instead of `and` for the boolean operator", "&&".to_string(), Applicability::MaybeIncorrect, ); } if self.token.is_ident_named(sym::or) { e.span_suggestion_short( self.token.span, "use `||` instead of `or` for the boolean operator", "||".to_string(), Applicability::MaybeIncorrect, ); } // Check to see if the user has written something like // //    if (cond) //      bar; // // which is valid in other languages, but not Rust. match self.parse_stmt_without_recovery(false) { Ok(Some(stmt)) => { if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace)) || do_not_suggest_help { // If the next token is an open brace (e.g., `if a b {`), the place- // inside-a-block suggestion would be more likely wrong than right. e.span_label(sp, "expected `{`"); return Err(e); </ins> } <del> Err(mut e) => { self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); e.cancel(); </del> <ins> let stmt_span = if self.eat(&token::Semi) { // Expand the span to include the semicolon. stmt.span.with_hi(self.prev_span.hi()) } else { stmt.span }; if let Ok(snippet) = self.span_to_snippet(stmt_span) { e.span_suggestion( stmt_span, "try placing this code inside a block", format!("{{ {} }}", snippet), // Speculative; has been misleading in the past (#46836). Applicability::MaybeIncorrect, ); </ins> } <del> _ => () </del> } <del> e.span_label(sp, "expected `{`"); return Err(e); </del> <ins> Err(mut e) => { self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); e.cancel(); } _ => {} </ins> } <del> self.parse_block_tail(lo, BlockCheckMode::Default) </del> <ins> e.span_label(sp, "expected `{`"); return Err(e); </ins> } /// Parses a block. Inner attributes are allowed.

self.maybe_annotate_with_ascription(&mut err, false); err.emit(); self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore); <del> Some(Stmt { id: DUMMY_NODE_ID, kind: StmtKind::Expr(self.mk_expr_err(self.token.span)), span: self.token.span, }) </del> <ins> Some(self.mk_stmt( self.token.span, StmtKind::Expr(self.mk_expr_err(self.token.span)), )) </ins> } Ok(stmt) => stmt, };

"this was erroneously allowed and will become a hard error in a future release" }).emit(); } <ins> fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt { Stmt { id: DUMMY_NODE_ID, kind, span } } </ins> }

}; } <ins> /// Instead of e.g. `vec![a, b, c]` in a pattern context, suggest `[a, b, c]`. fn suggest_slice_pat(e: &mut DiagnosticBuilder<'_>, site_span: Span, parser: &Parser<'_>) { let mut suggestion = None; if let Ok(code) = parser.sess.source_map().span_to_snippet(site_span) { if let Some(bang) = code.find('!') { suggestion = Some(code[bang + 1..].to_string()); } } if let Some(suggestion) = suggestion { e.span_suggestion( site_span, "use a slice pattern here instead", suggestion, Applicability::MachineApplicable, ); } else { e.span_label(site_span, "use a slice pattern here instead"); } e.help( "for more information, see https://doc.rust-lang.org/edition-guide/ rust-2018/slice-patterns.html" ); } </ins> impl<'a> ParserAnyMacro<'a> { crate fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment { let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self;

} match kind { AstFragmentKind::Pat if macro_ident.name == sym::vec => { <del> let mut suggestion = None; if let Ok(code) = parser.sess.source_map().span_to_snippet(site_span) { if let Some(bang) = code.find('!') { suggestion = Some(code[bang + 1..].to_string()); } } if let Some(suggestion) = suggestion { e.span_suggestion( site_span, "use a slice pattern here instead", suggestion, Applicability::MachineApplicable, ); } else { e.span_label( site_span, "use a slice pattern here instead", ); } e.help("for more information, see https://doc.rust-lang.org/edition-guide/ rust-2018/slice-patterns.html"); </del> <ins> suggest_slice_pat(&mut e, site_span, parser); </ins> } _ => annotate_err_with_kind(&mut e, kind, site_span), };