diff options
| author | Michael Goulet <michael@errs.io> | 2022-06-08 13:32:21 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-06-08 13:32:21 -0700 |
| commit | f12a1c23bc14788fd68a7f359290e9ab7759d1a1 (patch) | |
| tree | 3a6841f5c1456ac7bbef49192bc9db755250eac7 /compiler/rustc_parse | |
| parent | e0409200d978a377d4646e8da7be60483206ed64 (diff) | |
| parent | c1b1ec7e071b0f08985787a9a897bf78bc286e7e (diff) | |
| download | rust-f12a1c23bc14788fd68a7f359290e9ab7759d1a1.tar.gz rust-f12a1c23bc14788fd68a7f359290e9ab7759d1a1.zip | |
Rollup merge of #97857 - ChayimFriedman2:box-identifier-help, r=compiler-errors
Suggest escaping `box` as identifier Fixes #97810.
Diffstat (limited to 'compiler/rustc_parse')
| -rw-r--r-- | compiler/rustc_parse/src/parser/pat.rs | 61 |
1 files changed, 57 insertions, 4 deletions
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 2ad3f3ec19d..ca7915ed17a 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -360,10 +360,7 @@ impl<'a> Parser<'a> { let mutbl = self.parse_mutability(); self.parse_pat_ident(BindingMode::ByRef(mutbl))? } else if self.eat_keyword(kw::Box) { - // Parse `box pat` - let pat = self.parse_pat_with_range_pat(false, None)?; - self.sess.gated_spans.gate(sym::box_patterns, lo.to(self.prev_token.span)); - PatKind::Box(pat) + self.parse_pat_box()? } else if self.check_inline_const(0) { // Parse `const pat` let const_expr = self.parse_const_block(lo.to(self.token.span), true)?; @@ -915,6 +912,62 @@ impl<'a> Parser<'a> { Ok(PatKind::TupleStruct(qself, path, fields)) } + /// Are we sure this could not possibly be the start of a pattern? + /// + /// Currently, this only accounts for tokens that can follow identifiers + /// in patterns, but this can be extended as necessary. + fn isnt_pattern_start(&self) -> bool { + [ + token::Eq, + token::Colon, + token::Comma, + token::Semi, + token::At, + token::OpenDelim(Delimiter::Brace), + token::CloseDelim(Delimiter::Brace), + token::CloseDelim(Delimiter::Parenthesis), + ] + .contains(&self.token.kind) + } + + /// Parses `box pat` + fn parse_pat_box(&mut self) -> PResult<'a, PatKind> { + let box_span = self.prev_token.span; + + if self.isnt_pattern_start() { + self.struct_span_err( + self.token.span, + format!("expected pattern, found {}", super::token_descr(&self.token)), + ) + .span_note(box_span, "`box` is a reserved keyword") + .span_suggestion_verbose( + box_span.shrink_to_lo(), + "escape `box` to use it as an identifier", + "r#", + Applicability::MaybeIncorrect, + ) + .emit(); + + // We cannot use `parse_pat_ident()` since it will complain `box` + // is not an identifier. + let sub = if self.eat(&token::At) { + Some(self.parse_pat_no_top_alt(Some("binding pattern"))?) + } else { + None + }; + + Ok(PatKind::Ident( + BindingMode::ByValue(Mutability::Not), + Ident::new(kw::Box, box_span), + sub, + )) + } else { + let pat = self.parse_pat_with_range_pat(false, None)?; + self.sess.gated_spans.gate(sym::box_patterns, box_span.to(self.prev_token.span)); + Ok(PatKind::Box(pat)) + } + } + /// Parses the fields of a struct-like pattern. fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<PatField>, bool)> { let mut fields = Vec::new(); |
