diff options
Diffstat (limited to 'compiler/rustc_parse/src')
| -rw-r--r-- | compiler/rustc_parse/src/lexer/mod.rs | 31 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/mod.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/ty.rs | 40 |
3 files changed, 64 insertions, 11 deletions
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 8761c23625b..9fe8d9836ba 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -52,8 +52,15 @@ pub(crate) fn parse_token_trees<'a>( } let cursor = Cursor::new(src); - let string_reader = - StringReader { sess, start_pos, pos: start_pos, src, cursor, override_span }; + let string_reader = StringReader { + sess, + start_pos, + pos: start_pos, + src, + cursor, + override_span, + nbsp_is_whitespace: false, + }; tokentrees::TokenTreesReader::parse_all_token_trees(string_reader) } @@ -68,6 +75,10 @@ struct StringReader<'a> { /// Cursor for getting lexer tokens. cursor: Cursor<'a>, override_span: Option<Span>, + /// When a "unknown start of token: \u{a0}" has already been emitted earlier + /// in this file, it's safe to treat further occurrences of the non-breaking + /// space character as whitespace. + nbsp_is_whitespace: bool, } impl<'a> StringReader<'a> { @@ -239,6 +250,16 @@ impl<'a> StringReader<'a> { } let mut it = self.str_from_to_end(start).chars(); let c = it.next().unwrap(); + if c == '\u{00a0}' { + // If an error has already been reported on non-breaking + // space characters earlier in the file, treat all + // subsequent occurrences as whitespace. + if self.nbsp_is_whitespace { + preceded_by_whitespace = true; + continue; + } + self.nbsp_is_whitespace = true; + } let repeats = it.take_while(|c1| *c1 == c).count(); let mut err = self.struct_err_span_char(start, self.pos + Pos::from_usize(repeats * c.len_utf8()), "unknown start of token", c); @@ -486,7 +507,7 @@ impl<'a> StringReader<'a> { /// Slice of the source text from `start` up to but excluding `self.pos`, /// meaning the slice does not include the character `self.ch`. - fn str_from(&self, start: BytePos) -> &str { + fn str_from(&self, start: BytePos) -> &'a str { self.str_from_to(start, self.pos) } @@ -497,12 +518,12 @@ impl<'a> StringReader<'a> { } /// Slice of the source text spanning from `start` up to but excluding `end`. - fn str_from_to(&self, start: BytePos, end: BytePos) -> &str { + fn str_from_to(&self, start: BytePos, end: BytePos) -> &'a str { &self.src[self.src_index(start)..self.src_index(end)] } /// Slice of the source text spanning from `start` until the end - fn str_from_to_end(&self, start: BytePos) -> &str { + fn str_from_to_end(&self, start: BytePos) -> &'a str { &self.src[self.src_index(start)..] } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 2fd2a4e5154..ffb23b50a16 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -542,9 +542,9 @@ impl<'a> Parser<'a> { } } - /// Expect next token to be edible or inedible token. If edible, + /// Expect next token to be edible or inedible token. If edible, /// then consume it; if inedible, then return without consuming - /// anything. Signal a fatal error if next token is unexpected. + /// anything. Signal a fatal error if next token is unexpected. pub fn expect_one_of( &mut self, edible: &[TokenKind], diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index a6f702e5428..1766b0293de 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -727,11 +727,13 @@ impl<'a> Parser<'a> { let mut bounds = Vec::new(); let mut negative_bounds = Vec::new(); + // In addition to looping while we find generic bounds: + // We continue even if we find a keyword. This is necessary for error recovery on, + // for example, `impl fn()`. The only keyword that can go after generic bounds is + // `where`, so stop if it's it. + // We also continue if we find types (not traits), again for error recovery. while self.can_begin_bound() - // Continue even if we find a keyword. - // This is necessary for error recover on, for example, `impl fn()`. - // - // The only keyword that can go after generic bounds is `where`, so stop if it's it. + || self.token.can_begin_type() || (self.token.is_reserved_ident() && !self.token.is_keyword(kw::Where)) { if self.token.is_keyword(kw::Dyn) { @@ -939,6 +941,36 @@ impl<'a> Parser<'a> { && let Some(path) = self.recover_path_from_fn() { path + } else if !self.token.is_path_start() && self.token.can_begin_type() { + let ty = self.parse_ty_no_plus()?; + // Instead of finding a path (a trait), we found a type. + let mut err = self.struct_span_err(ty.span, "expected a trait, found type"); + + // If we can recover, try to extract a path from the type. Note + // that we do not use the try operator when parsing the type because + // if it fails then we get a parser error which we don't want (we're trying + // to recover from errors, not make more). + let path = if self.may_recover() + && matches!(ty.kind, TyKind::Ptr(..) | TyKind::Ref(..)) + && let TyKind::Path(_, path) = &ty.peel_refs().kind { + // Just get the indirection part of the type. + let span = ty.span.until(path.span); + + err.span_suggestion_verbose( + span, + "consider removing the indirection", + "", + Applicability::MaybeIncorrect, + ); + + path.clone() + } else { + return Err(err); + }; + + err.emit(); + + path } else { self.parse_path(PathStyle::Type)? }; |
