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), 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(self.close_delim_err(delim))
39 };
40 } else if self.token.kind == token::Eof {
41 return if is_delimited {
42 Err(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, 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 if Delimiter::Brace == open_delim
96 && let Some(TokenTree::Token(tok, _)) = tts.iter().next()
97 && #[allow(non_exhaustive_omitted_patterns)] match tok.kind {
token::AndAnd | token::OrOr => true,
_ => false,
}matches!(tok.kind, token::AndAnd | token::OrOr)
98 {
99 self.diag_info.if_let_chain_hint_spans.push(tok.span);
100 }
101
102 self.bump_minimal()
104 } else {
105 let mut unclosed_delimiter = None;
107 let mut candidate = None;
108
109 if self.diag_info.last_unclosed_found_span != Some(self.token.span) {
110 self.diag_info.last_unclosed_found_span = Some(self.token.span);
112 if let Some(&(_, sp)) = self.diag_info.open_delimiters.last() {
116 unclosed_delimiter = Some(sp);
117 };
118 for (delimiter, delimiter_span) in &self.diag_info.open_delimiters {
119 if same_indentation_level(sm, self.token.span, *delimiter_span)
120 && delimiter == &close_delim
121 {
122 candidate = Some(*delimiter_span);
124 }
125 }
126 self.diag_info.open_delimiters.pop().unwrap();
127 self.diag_info.unmatched_delims.push(UnmatchedDelim {
128 found_delim: Some(close_delim),
129 found_span: self.token.span,
130 unclosed_span: unclosed_delimiter,
131 candidate_span: candidate,
132 });
133 } else {
134 self.diag_info.open_delimiters.pop();
135 }
136
137 if !self.diag_info.open_delimiters.iter().any(|&(d, _)| d == close_delim) {
145 self.bump_minimal()
146 } else {
147 Spacing::Alone
149 }
150 }
151 } else {
152 {
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);
153 Spacing::Alone
158 };
159
160 let spacing = DelimSpacing::new(open_spacing, close_spacing);
161
162 Ok(TokenTree::Delimited(delim_span, spacing, open_delim, tts))
163 }
164
165 fn bump(&mut self) -> (Token, Spacing) {
168 let (this_spacing, next_tok) = loop {
169 let (next_tok, is_next_tok_preceded_by_whitespace) = self.next_token_from_cursor();
170
171 if is_next_tok_preceded_by_whitespace {
172 break (Spacing::Alone, next_tok);
173 } else if let Some(glued) = self.token.glue(&next_tok) {
174 self.token = glued;
175 } else {
176 let this_spacing = self.calculate_spacing(&next_tok);
177 break (this_spacing, next_tok);
178 }
179 };
180 let this_tok = std::mem::replace(&mut self.token, next_tok);
181 (this_tok, this_spacing)
182 }
183
184 fn bump_minimal(&mut self) -> Spacing {
186 let (next_tok, is_next_tok_preceded_by_whitespace) = self.next_token_from_cursor();
187 let this_spacing = if is_next_tok_preceded_by_whitespace {
188 Spacing::Alone
189 } else {
190 self.calculate_spacing(&next_tok)
191 };
192 self.token = next_tok;
193 this_spacing
194 }
195
196 fn calculate_spacing(&self, next_tok: &Token) -> Spacing {
197 if next_tok.is_punct() {
198 Spacing::Joint
199 } else if *next_tok == token::Eof {
200 Spacing::Alone
201 } else {
202 Spacing::JointHidden
203 }
204 }
205
206 fn eof_err(&mut self) -> Diag<'psess> {
207 const UNCLOSED_DELIMITER_SHOW_LIMIT: usize = 5;
208 let msg = "this file contains an unclosed delimiter";
209 let mut err = self.dcx().struct_span_err(self.token.span, msg);
210
211 let len = usize::min(UNCLOSED_DELIMITER_SHOW_LIMIT, self.diag_info.open_delimiters.len());
212 for &(_, span) in &self.diag_info.open_delimiters[..len] {
213 err.span_label(span, "unclosed delimiter");
214 self.diag_info.unmatched_delims.push(UnmatchedDelim {
215 found_delim: None,
216 found_span: self.token.span,
217 unclosed_span: Some(span),
218 candidate_span: None,
219 });
220 }
221
222 if let Some((_, span)) = self.diag_info.open_delimiters.get(UNCLOSED_DELIMITER_SHOW_LIMIT)
223 && self.diag_info.open_delimiters.len() >= UNCLOSED_DELIMITER_SHOW_LIMIT + 2
224 {
225 err.span_label(
226 *span,
227 ::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!(
228 "another {} unclosed delimiters begin from here",
229 self.diag_info.open_delimiters.len() - UNCLOSED_DELIMITER_SHOW_LIMIT
230 ),
231 );
232 }
233
234 if let Some((delim, _)) = self.diag_info.open_delimiters.last() {
235 report_suspicious_mismatch_block(
236 &mut err,
237 &self.diag_info,
238 self.psess.source_map(),
239 *delim,
240 )
241 }
242 err
243 }
244
245 fn close_delim_err(&mut self, delim: Delimiter) -> Diag<'psess> {
246 let token_str = token_to_string(&self.token);
248 let msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unexpected closing delimiter: `{0}`",
token_str))
})format!("unexpected closing delimiter: `{token_str}`");
249 let mut err = self.dcx().struct_span_err(self.token.span, msg);
250
251 if !report_missing_open_delim(&mut err, &mut self.diag_info.unmatched_delims) {
253 report_suspicious_mismatch_block(
254 &mut err,
255 &self.diag_info,
256 self.psess.source_map(),
257 delim,
258 );
259 }
260
261 err.span_label(self.token.span, "unexpected closing delimiter");
262 err
263 }
264}