diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-09-23 04:48:22 +0200 |
|---|---|---|
| committer | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-09-23 17:50:07 +0200 |
| commit | 62d85849d0a9a828dc58a1820469daf80a2b5b52 (patch) | |
| tree | ff7f14d0b574eee7d77ce3dd79e185738e002a06 /src/libsyntax/parse/parser | |
| parent | ae8b3e8fc6e95a0f68fc49338f394d670e233883 (diff) | |
| download | rust-62d85849d0a9a828dc58a1820469daf80a2b5b52.tar.gz rust-62d85849d0a9a828dc58a1820469daf80a2b5b52.zip | |
Add parser recovery for `const $ident = $expr;`.
Then use the diagnostics-stealing API to stash parser errors and enrich them with type information in typeck.
Diffstat (limited to 'src/libsyntax/parse/parser')
| -rw-r--r-- | src/libsyntax/parse/parser/item.rs | 47 |
1 files changed, 44 insertions, 3 deletions
diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index cf196645e4f..0d073f0cc97 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -24,7 +24,7 @@ use crate::symbol::{kw, sym}; use std::mem; use log::debug; use rustc_target::spec::abi::Abi; -use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use errors::{Applicability, DiagnosticBuilder, DiagnosticId, StashKey}; /// Whether the type alias or associated type is a concrete type or an opaque type. #[derive(Debug)] @@ -1477,10 +1477,23 @@ impl<'a> Parser<'a> { } } + /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty = $expr` with + /// `["const" | ("static" "mut"?)]` already parsed and stored in `m`. + /// + /// When `m` is `"const"`, `$ident` may also be `"_"`. fn parse_item_const(&mut self, m: Option<Mutability>) -> PResult<'a, ItemInfo> { let id = if m.is_none() { self.parse_ident_or_underscore() } else { self.parse_ident() }?; - self.expect(&token::Colon)?; - let ty = self.parse_ty()?; + + // Parse the type of a `const` or `static mut?` item. + // That is, the `":" $ty` fragment. + let ty = if self.token == token::Eq { + self.recover_missing_const_type(id, m) + } else { + // Not `=` so expect `":"" $ty` as usual. + self.expect(&token::Colon)?; + self.parse_ty()? + }; + self.expect(&token::Eq)?; let e = self.parse_expr()?; self.expect(&token::Semi)?; @@ -1491,6 +1504,34 @@ impl<'a> Parser<'a> { Ok((id, item, None)) } + /// We were supposed to parse `:` but instead, we're already at `=`. + /// This means that the type is missing. + fn recover_missing_const_type(&mut self, id: Ident, m: Option<Mutability>) -> P<Ty> { + // Construct the error and stash it away with the hope + // that typeck will later enrich the error with a type. + let kind = match m { + Some(Mutability::Mutable) => "static mut", + Some(Mutability::Immutable) => "static", + None => "const", + }; + let mut err = self.struct_span_err(id.span, &format!("missing type for `{}` item", kind)); + err.span_suggestion( + id.span, + "provide a type for the item", + format!("{}: <type>", id), + Applicability::HasPlaceholders, + ); + err.stash(id.span, StashKey::ItemNoType); + + // The user intended that the type be inferred, + // so treat this as if the user wrote e.g. `const A: _ = expr;`. + P(Ty { + node: TyKind::Infer, + span: id.span, + id: ast::DUMMY_NODE_ID, + }) + } + /// Parses `type Foo = Bar;` or returns `None` /// without modifying the parser state. fn eat_type(&mut self) -> Option<PResult<'a, (Ident, AliasKind, Generics)>> { |
