diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2021-05-01 12:58:15 -0700 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2021-05-11 18:48:57 -0700 |
| commit | 7697ce4560b7799f5fb7e48524b5a347ba893b4e (patch) | |
| tree | b0b0ff87e0ac2fb1e7b72bafa3a03a10ddfcee6f /compiler/rustc_parse/src/parser | |
| parent | 890803d3722b5cf8810ae1f49b4d9f062a87c927 (diff) | |
| download | rust-7697ce4560b7799f5fb7e48524b5a347ba893b4e.tar.gz rust-7697ce4560b7799f5fb7e48524b5a347ba893b4e.zip | |
Recover from invalid `struct` item syntax
Parse unsupported "default field const values":
```rust
struct S {
field: Type = const_val,
}
```
Recover from small `:` typo and provide suggestion:
```rust
struct S {
field; Type,
field2= Type,
}
```
Diffstat (limited to 'compiler/rustc_parse/src/parser')
| -rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 553ffda814f..b2b578f1ed4 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1399,6 +1399,37 @@ impl<'a> Parser<'a> { Ok(a_var) } + fn expect_field_ty_separator(&mut self) -> PResult<'a, ()> { + if let Err(mut err) = self.expect(&token::Colon) { + let sm = self.sess.source_map(); + let eq_typo = self.token.kind == token::Eq && self.look_ahead(1, |t| t.is_path_start()); + let semi_typo = self.token.kind == token::Semi + && self.look_ahead(1, |t| { + t.is_path_start() + // We check that we are in a situation like `foo; bar` to avoid bad suggestions + // when there's no type and `;` was used instead of a comma. + && match (sm.lookup_line(self.token.span.hi()), sm.lookup_line(t.span.lo())) { + (Ok(l), Ok(r)) => l.line == r.line, + _ => true, + } + }); + if eq_typo || semi_typo { + self.bump(); + // Gracefully handle small typos. + err.span_suggestion_short( + self.prev_token.span, + "field names and their types are separated with `:`", + ":".to_string(), + Applicability::MachineApplicable, + ); + err.emit(); + } else { + return Err(err); + } + } + Ok(()) + } + /// Parses a structure field. fn parse_name_and_ty( &mut self, @@ -1408,8 +1439,21 @@ impl<'a> Parser<'a> { attrs: Vec<Attribute>, ) -> PResult<'a, FieldDef> { let name = self.parse_field_ident(adt_ty, lo)?; - self.expect(&token::Colon)?; + self.expect_field_ty_separator()?; let ty = self.parse_ty()?; + if self.token.kind == token::Eq { + self.bump(); + let const_expr = self.parse_anon_const_expr()?; + let sp = ty.span.shrink_to_hi().to(const_expr.value.span); + self.struct_span_err(sp, "default values on `struct` fields aren't supported") + .span_suggestion( + sp, + "remove this unsupported default value", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + } Ok(FieldDef { span: lo.to(self.prev_token.span), ident: Some(name), |
