diff options
Diffstat (limited to 'compiler/rustc_parse/src')
| -rw-r--r-- | compiler/rustc_parse/src/lexer/diagnostics.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/lexer/mod.rs | 31 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/lexer/tokentrees.rs | 27 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/lib.rs | 32 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/diagnostics.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/mod.rs | 10 |
6 files changed, 60 insertions, 56 deletions
diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs index 386bf026bb4..27f4428d306 100644 --- a/compiler/rustc_parse/src/lexer/diagnostics.rs +++ b/compiler/rustc_parse/src/lexer/diagnostics.rs @@ -1,4 +1,4 @@ -use super::UnmatchedBrace; +use super::UnmatchedDelim; use rustc_ast::token::Delimiter; use rustc_errors::Diagnostic; use rustc_span::source_map::SourceMap; @@ -8,7 +8,7 @@ use rustc_span::Span; pub struct TokenTreeDiagInfo { /// Stack of open delimiters and their spans. Used for error message. pub open_braces: Vec<(Delimiter, Span)>, - pub unmatched_braces: Vec<UnmatchedBrace>, + pub unmatched_delims: Vec<UnmatchedDelim>, /// Used only for error recovery when arriving to EOF with mismatched braces. pub last_unclosed_found_span: Option<Span>, @@ -32,10 +32,10 @@ pub fn same_identation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> b // it's more friendly compared to report `unmatched error` in later phase pub fn report_missing_open_delim( err: &mut Diagnostic, - unmatched_braces: &[UnmatchedBrace], + unmatched_delims: &[UnmatchedDelim], ) -> bool { let mut reported_missing_open = false; - for unmatch_brace in unmatched_braces.iter() { + for unmatch_brace in unmatched_delims.iter() { if let Some(delim) = unmatch_brace.found_delim && matches!(delim, Delimiter::Parenthesis | Delimiter::Bracket) { @@ -60,7 +60,7 @@ pub fn report_suspicious_mismatch_block( sm: &SourceMap, delim: Delimiter, ) { - if report_missing_open_delim(err, &diag_info.unmatched_braces) { + if report_missing_open_delim(err, &diag_info.unmatched_delims) { return; } diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 37449aaabed..9dbddee5a56 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -1,10 +1,11 @@ use crate::errors; use crate::lexer::unicode_chars::UNICODE_ARRAY; +use crate::make_unclosed_delims_error; use rustc_ast::ast::{self, AttrStyle}; use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::unicode::contains_text_flow_control_chars; -use rustc_errors::{error_code, Applicability, DiagnosticBuilder, PResult, StashKey}; +use rustc_errors::{error_code, Applicability, Diagnostic, DiagnosticBuilder, StashKey}; use rustc_lexer::unescape::{self, Mode}; use rustc_lexer::Cursor; use rustc_lexer::{Base, DocStyle, RawStrError}; @@ -31,7 +32,7 @@ use unescape_error_reporting::{emit_unescape_error, escaped_char}; rustc_data_structures::static_assert_size!(rustc_lexer::Token, 12); #[derive(Clone, Debug)] -pub struct UnmatchedBrace { +pub struct UnmatchedDelim { pub expected_delim: Delimiter, pub found_delim: Option<Delimiter>, pub found_span: Span, @@ -44,7 +45,7 @@ pub(crate) fn parse_token_trees<'a>( mut src: &'a str, mut start_pos: BytePos, override_span: Option<Span>, -) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) { +) -> Result<TokenStream, Vec<Diagnostic>> { // Skip `#!`, if present. if let Some(shebang_len) = rustc_lexer::strip_shebang(src) { src = &src[shebang_len..]; @@ -61,7 +62,29 @@ pub(crate) fn parse_token_trees<'a>( override_span, nbsp_is_whitespace: false, }; - tokentrees::TokenTreesReader::parse_all_token_trees(string_reader) + let (token_trees, unmatched_delims) = + tokentrees::TokenTreesReader::parse_all_token_trees(string_reader); + match token_trees { + Ok(stream) if unmatched_delims.is_empty() => Ok(stream), + _ => { + // Return error if there are unmatched delimiters or unclosng delimiters. + // We emit delimiter mismatch errors first, then emit the unclosing delimiter mismatch + // because the delimiter mismatch is more likely to be the root cause of error + + let mut buffer = Vec::with_capacity(1); + // Not using `emit_unclosed_delims` to use `db.buffer` + for unmatched in unmatched_delims { + if let Some(err) = make_unclosed_delims_error(unmatched, &sess) { + err.buffer(&mut buffer); + } + } + if let Err(err) = token_trees { + // Add unclosing delimiter error + err.buffer(&mut buffer); + } + Err(buffer) + } + } } struct StringReader<'a> { diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index 0de8f79112c..36fd1e37d65 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -1,7 +1,7 @@ use super::diagnostics::report_suspicious_mismatch_block; use super::diagnostics::same_identation_level; use super::diagnostics::TokenTreeDiagInfo; -use super::{StringReader, UnmatchedBrace}; +use super::{StringReader, UnmatchedDelim}; use rustc_ast::token::{self, Delimiter, Token}; use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast_pretty::pprust::token_to_string; @@ -18,14 +18,14 @@ pub(super) struct TokenTreesReader<'a> { impl<'a> TokenTreesReader<'a> { pub(super) fn parse_all_token_trees( string_reader: StringReader<'a>, - ) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) { + ) -> (PResult<'a, TokenStream>, Vec<UnmatchedDelim>) { let mut tt_reader = TokenTreesReader { string_reader, token: Token::dummy(), diag_info: TokenTreeDiagInfo::default(), }; let res = tt_reader.parse_token_trees(/* is_delimited */ false); - (res, tt_reader.diag_info.unmatched_braces) + (res, tt_reader.diag_info.unmatched_delims) } // Parse a stream of tokens into a list of `TokenTree`s. @@ -34,7 +34,7 @@ impl<'a> TokenTreesReader<'a> { let mut buf = Vec::new(); loop { match self.token.kind { - token::OpenDelim(delim) => buf.push(self.parse_token_tree_open_delim(delim)), + token::OpenDelim(delim) => buf.push(self.parse_token_tree_open_delim(delim)?), token::CloseDelim(delim) => { return if is_delimited { Ok(TokenStream::new(buf)) @@ -43,10 +43,11 @@ impl<'a> TokenTreesReader<'a> { }; } token::Eof => { - if is_delimited { - self.eof_err().emit(); - } - return Ok(TokenStream::new(buf)); + return if is_delimited { + Err(self.eof_err()) + } else { + Ok(TokenStream::new(buf)) + }; } _ => { // Get the next normal token. This might require getting multiple adjacent @@ -78,7 +79,7 @@ impl<'a> TokenTreesReader<'a> { let mut err = self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, msg); for &(_, sp) in &self.diag_info.open_braces { err.span_label(sp, "unclosed delimiter"); - self.diag_info.unmatched_braces.push(UnmatchedBrace { + self.diag_info.unmatched_delims.push(UnmatchedDelim { expected_delim: Delimiter::Brace, found_delim: None, found_span: self.token.span, @@ -98,7 +99,7 @@ impl<'a> TokenTreesReader<'a> { err } - fn parse_token_tree_open_delim(&mut self, open_delim: Delimiter) -> TokenTree { + fn parse_token_tree_open_delim(&mut self, open_delim: Delimiter) -> PResult<'a, TokenTree> { // The span for beginning of the delimited section let pre_span = self.token.span; @@ -107,7 +108,7 @@ impl<'a> TokenTreesReader<'a> { // Parse the token trees within the delimiters. // We stop at any delimiter so we can try to recover if the user // uses an incorrect delimiter. - let tts = self.parse_token_trees(/* is_delimited */ true).unwrap(); + let tts = self.parse_token_trees(/* is_delimited */ true)?; // Expand to cover the entire delimited token tree let delim_span = DelimSpan::from_pair(pre_span, self.token.span); @@ -160,7 +161,7 @@ impl<'a> TokenTreesReader<'a> { } } let (tok, _) = self.diag_info.open_braces.pop().unwrap(); - self.diag_info.unmatched_braces.push(UnmatchedBrace { + self.diag_info.unmatched_delims.push(UnmatchedDelim { expected_delim: tok, found_delim: Some(close_delim), found_span: self.token.span, @@ -190,7 +191,7 @@ impl<'a> TokenTreesReader<'a> { _ => unreachable!(), } - TokenTree::Delimited(delim_span, open_delim, tts) + Ok(TokenTree::Delimited(delim_span, open_delim, tts)) } fn close_delim_err(&mut self, delim: Delimiter) -> PErr<'a> { diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 6f37e9758fc..d1c3fd0cd0f 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -30,7 +30,7 @@ pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments"); #[macro_use] pub mod parser; -use parser::{emit_unclosed_delims, make_unclosed_delims_error, Parser}; +use parser::{make_unclosed_delims_error, Parser}; pub mod lexer; pub mod validate_attr; @@ -96,10 +96,7 @@ pub fn parse_stream_from_source_str( sess: &ParseSess, override_span: Option<Span>, ) -> TokenStream { - let (stream, mut errors) = - source_file_to_stream(sess, sess.source_map().new_source_file(name, source), override_span); - emit_unclosed_delims(&mut errors, &sess); - stream + source_file_to_stream(sess, sess.source_map().new_source_file(name, source), override_span) } /// Creates a new parser from a source string. @@ -135,9 +132,8 @@ fn maybe_source_file_to_parser( source_file: Lrc<SourceFile>, ) -> Result<Parser<'_>, Vec<Diagnostic>> { let end_pos = source_file.end_pos; - let (stream, unclosed_delims) = maybe_file_to_stream(sess, source_file, None)?; + let stream = maybe_file_to_stream(sess, source_file, None)?; let mut parser = stream_to_parser(sess, stream, None); - parser.unclosed_delims = unclosed_delims; if parser.token == token::Eof { parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt(), None); } @@ -182,7 +178,7 @@ pub fn source_file_to_stream( sess: &ParseSess, source_file: Lrc<SourceFile>, override_span: Option<Span>, -) -> (TokenStream, Vec<lexer::UnmatchedBrace>) { +) -> TokenStream { panictry_buffer!(&sess.span_diagnostic, maybe_file_to_stream(sess, source_file, override_span)) } @@ -192,7 +188,7 @@ pub fn maybe_file_to_stream( sess: &ParseSess, source_file: Lrc<SourceFile>, override_span: Option<Span>, -) -> Result<(TokenStream, Vec<lexer::UnmatchedBrace>), Vec<Diagnostic>> { +) -> Result<TokenStream, Vec<Diagnostic>> { let src = source_file.src.as_ref().unwrap_or_else(|| { sess.span_diagnostic.bug(&format!( "cannot lex `source_file` without source: {}", @@ -200,23 +196,7 @@ pub fn maybe_file_to_stream( )); }); - let (token_trees, unmatched_braces) = - lexer::parse_token_trees(sess, src.as_str(), source_file.start_pos, override_span); - - match token_trees { - Ok(stream) => Ok((stream, unmatched_braces)), - Err(err) => { - let mut buffer = Vec::with_capacity(1); - err.buffer(&mut buffer); - // Not using `emit_unclosed_delims` to use `db.buffer` - for unmatched in unmatched_braces { - if let Some(err) = make_unclosed_delims_error(unmatched, &sess) { - err.buffer(&mut buffer); - } - } - Err(buffer) - } - } + lexer::parse_token_trees(sess, src.as_str(), source_file.start_pos, override_span) } /// Given a stream and the `ParseSess`, produces a parser. diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index b4948dddcc9..488f14699c3 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -19,7 +19,7 @@ use crate::errors::{ }; use crate::fluent_generated as fluent; -use crate::lexer::UnmatchedBrace; +use crate::lexer::UnmatchedDelim; use crate::parser; use rustc_ast as ast; use rustc_ast::ptr::P; @@ -222,7 +222,7 @@ impl MultiSugg { /// is dropped. pub struct SnapshotParser<'a> { parser: Parser<'a>, - unclosed_delims: Vec<UnmatchedBrace>, + unclosed_delims: Vec<UnmatchedDelim>, } impl<'a> Deref for SnapshotParser<'a> { @@ -264,7 +264,7 @@ impl<'a> Parser<'a> { self.unclosed_delims.extend(snapshot.unclosed_delims); } - pub fn unclosed_delims(&self) -> &[UnmatchedBrace] { + pub fn unclosed_delims(&self) -> &[UnmatchedDelim] { &self.unclosed_delims } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index fda9151478f..b1b79fe4e05 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -10,7 +10,7 @@ mod path; mod stmt; mod ty; -use crate::lexer::UnmatchedBrace; +use crate::lexer::UnmatchedDelim; pub use attr_wrapper::AttrWrapper; pub use diagnostics::AttemptLocalParseRecovery; pub(crate) use item::FnParseMode; @@ -149,7 +149,7 @@ pub struct Parser<'a> { /// A list of all unclosed delimiters found by the lexer. If an entry is used for error recovery /// it gets removed from here. Every entry left at the end gets emitted as an independent /// error. - pub(super) unclosed_delims: Vec<UnmatchedBrace>, + pub(super) unclosed_delims: Vec<UnmatchedDelim>, last_unexpected_token_span: Option<Span>, /// Span pointing at the `:` for the last type ascription the parser has seen, and whether it /// looked like it could have been a mistyped path or literal `Option:Some(42)`). @@ -1521,11 +1521,11 @@ impl<'a> Parser<'a> { } pub(crate) fn make_unclosed_delims_error( - unmatched: UnmatchedBrace, + unmatched: UnmatchedDelim, sess: &ParseSess, ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> { // `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to - // `unmatched_braces` only for error recovery in the `Parser`. + // `unmatched_delims` only for error recovery in the `Parser`. let found_delim = unmatched.found_delim?; let mut spans = vec![unmatched.found_span]; if let Some(sp) = unmatched.unclosed_span { @@ -1542,7 +1542,7 @@ pub(crate) fn make_unclosed_delims_error( Some(err) } -pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedBrace>, sess: &ParseSess) { +pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedDelim>, sess: &ParseSess) { *sess.reached_eof.borrow_mut() |= unclosed_delims.iter().any(|unmatched_delim| unmatched_delim.found_delim.is_none()); for unmatched in unclosed_delims.drain(..) { |
