1use rustc_ast::token::{self, Delimiter, Token};
2use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
3use rustc_ast_pretty::pprust::token_to_string;
4use rustc_errors::Diag;
5
6use super::diagnostics::{
7 report_missing_open_delim, report_suspicious_mismatch_block, same_indentation_level,
8};
9use super::{Lexer, UnmatchedDelim};
10
11impl<'psess, 'src> Lexer<'psess, 'src> {
12 pub(super) fn lex_token_trees(
15 &mut self,
16 is_delimited: bool,
17 ) -> Result<(Spacing, TokenStream), Vec<Diag<'psess>>> {
18 let open_spacing = self.bump_minimal();
20
21 let mut buf = Vec::new();
22 loop {
23 if let Some(delim) = self.token.kind.open_delim() {
24 if true {
if !!#[allow(non_exhaustive_omitted_patterns)] match delim {
Delimiter::Invisible(_) => true,
_ => false,
} {
::core::panicking::panic("assertion failed: !matches!(delim, Delimiter::Invisible(_))")
};
};debug_assert!(!matches!(delim, Delimiter::Invisible(_)));
27 buf.push(match self.lex_token_tree_open_delim(delim) {
28 Ok(val) => val,
29 Err(errs) => return Err(errs),
30 })
31 } else if let Some(delim) = self.token.kind.close_delim() {
32 if true {
if !!#[allow(non_exhaustive_omitted_patterns)] match delim {
Delimiter::Invisible(_) => true,
_ => false,
} {
::core::panicking::panic("assertion failed: !matches!(delim, Delimiter::Invisible(_))")
};
};debug_assert!(!matches!(delim, Delimiter::Invisible(_)));
35 return if is_delimited {
36 Ok((open_spacing, TokenStream::new(buf)))
37 } else {
38 Err(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[self.close_delim_err(delim)]))vec![self.close_delim_err(delim)])
39 };
40 } else if self.token.kind == token::Eof {
41 return if is_delimited {
42 Err(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[self.eof_err()]))vec![self.eof_err()])
43 } else {
44 Ok((open_spacing, TokenStream::new(buf)))
45 };
46 } else {
47 let (this_tok, this_spacing) = self.bump();
49 buf.push(TokenTree::Token(this_tok, this_spacing));
50 }
51 }
52 }
53
54 fn lex_token_tree_open_delim(
55 &mut self,
56 open_delim: Delimiter,
57 ) -> Result<TokenTree, Vec<Diag<'psess>>> {
58 let pre_span = self.token.span;
60
61 self.diag_info.open_delimiters.push((open_delim, self.token.span));
62
63 let (open_spacing, tts) = self.lex_token_trees(true)?;
67
68 let delim_span = DelimSpan::from_pair(pre_span, self.token.span);
70 let sm = self.psess.source_map();
71
72 let close_spacing = if let Some(close_delim) = self.token.kind.close_delim() {
73 if close_delim == open_delim {
74 self.diag_info.open_delimiters.pop().unwrap();
76 let close_delimiter_span = self.token.span;
77
78 if tts.is_empty() && close_delim == Delimiter::Brace {
79 let empty_block_span = pre_span.to(close_delimiter_span);
80 if !sm.is_multiline(empty_block_span) {
81 self.diag_info.empty_block_spans.push(empty_block_span);
84 }
85 }
86
87 if Delimiter::Brace == open_delim {
89 self.diag_info.matching_block_spans.push((pre_span, close_delimiter_span));
91 }
92
93 self.bump_minimal()
95 } else {
96 let mut unclosed_delimiter = None;
98 let mut candidate = None;
99
100 if self.diag_info.last_unclosed_found_span != Some(self.token.span) {
101 self.diag_info.last_unclosed_found_span = Some(self.token.span);
103 if let Some(&(_, sp)) = self.diag_info.open_delimiters.last() {
107 unclosed_delimiter = Some(sp);
108 };
109 for (delimiter, delimiter_span) in &self.diag_info.open_delimiters {
110 if same_indentation_level(sm, self.token.span, *delimiter_span)
111 && delimiter == &close_delim
112 {
113 candidate = Some(*delimiter_span);
115 }
116 }
117 self.diag_info.open_delimiters.pop().unwrap();
118 self.diag_info.unmatched_delims.push(UnmatchedDelim {
119 found_delim: Some(close_delim),
120 found_span: self.token.span,
121 unclosed_span: unclosed_delimiter,
122 candidate_span: candidate,
123 });
124 } else {
125 self.diag_info.open_delimiters.pop();
126 }
127
128 if !self.diag_info.open_delimiters.iter().any(|&(d, _)| d == close_delim) {
136 self.bump_minimal()
137 } else {
138 Spacing::Alone
140 }
141 }
142 } else {
143 match (&self.token.kind, &token::Eof) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val, &*right_val,
::core::option::Option::None);
}
}
};assert_eq!(self.token.kind, token::Eof);
144 Spacing::Alone
149 };
150
151 let spacing = DelimSpacing::new(open_spacing, close_spacing);
152
153 Ok(TokenTree::Delimited(delim_span, spacing, open_delim, tts))
154 }
155
156 fn bump(&mut self) -> (Token, Spacing) {
159 let (this_spacing, next_tok) = loop {
160 let (next_tok, is_next_tok_preceded_by_whitespace) = self.next_token_from_cursor();
161
162 if is_next_tok_preceded_by_whitespace {
163 break (Spacing::Alone, next_tok);
164 } else if let Some(glued) = self.token.glue(&next_tok) {
165 self.token = glued;
166 } else {
167 let this_spacing = self.calculate_spacing(&next_tok);
168 break (this_spacing, next_tok);
169 }
170 };
171 let this_tok = std::mem::replace(&mut self.token, next_tok);
172 (this_tok, this_spacing)
173 }
174
175 fn bump_minimal(&mut self) -> Spacing {
177 let (next_tok, is_next_tok_preceded_by_whitespace) = self.next_token_from_cursor();
178 let this_spacing = if is_next_tok_preceded_by_whitespace {
179 Spacing::Alone
180 } else {
181 self.calculate_spacing(&next_tok)
182 };
183 self.token = next_tok;
184 this_spacing
185 }
186
187 fn calculate_spacing(&self, next_tok: &Token) -> Spacing {
188 if next_tok.is_punct() {
189 Spacing::Joint
190 } else if *next_tok == token::Eof {
191 Spacing::Alone
192 } else {
193 Spacing::JointHidden
194 }
195 }
196
197 fn eof_err(&mut self) -> Diag<'psess> {
198 const UNCLOSED_DELIMITER_SHOW_LIMIT: usize = 5;
199 let msg = "this file contains an unclosed delimiter";
200 let mut err = self.dcx().struct_span_err(self.token.span, msg);
201
202 let len = usize::min(UNCLOSED_DELIMITER_SHOW_LIMIT, self.diag_info.open_delimiters.len());
203 for &(_, span) in &self.diag_info.open_delimiters[..len] {
204 err.span_label(span, "unclosed delimiter");
205 self.diag_info.unmatched_delims.push(UnmatchedDelim {
206 found_delim: None,
207 found_span: self.token.span,
208 unclosed_span: Some(span),
209 candidate_span: None,
210 });
211 }
212
213 if let Some((_, span)) = self.diag_info.open_delimiters.get(UNCLOSED_DELIMITER_SHOW_LIMIT)
214 && self.diag_info.open_delimiters.len() >= UNCLOSED_DELIMITER_SHOW_LIMIT + 2
215 {
216 err.span_label(
217 *span,
218 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("another {0} unclosed delimiters begin from here",
self.diag_info.open_delimiters.len() -
UNCLOSED_DELIMITER_SHOW_LIMIT))
})format!(
219 "another {} unclosed delimiters begin from here",
220 self.diag_info.open_delimiters.len() - UNCLOSED_DELIMITER_SHOW_LIMIT
221 ),
222 );
223 }
224
225 if let Some((delim, _)) = self.diag_info.open_delimiters.last() {
226 report_suspicious_mismatch_block(
227 &mut err,
228 &self.diag_info,
229 self.psess.source_map(),
230 *delim,
231 )
232 }
233 err
234 }
235
236 fn close_delim_err(&mut self, delim: Delimiter) -> Diag<'psess> {
237 let token_str = token_to_string(&self.token);
239 let msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unexpected closing delimiter: `{0}`",
token_str))
})format!("unexpected closing delimiter: `{token_str}`");
240 let mut err = self.dcx().struct_span_err(self.token.span, msg);
241
242 if !report_missing_open_delim(&mut err, &mut self.diag_info.unmatched_delims) {
244 report_suspicious_mismatch_block(
245 &mut err,
246 &self.diag_info,
247 self.psess.source_map(),
248 delim,
249 );
250 }
251
252 err.span_label(self.token.span, "unexpected closing delimiter");
253 err
254 }
255}