@@ -3,7 +3,7 @@ use rustc_ast::token::{self, Delimiter, Token};
33use  rustc_ast:: tokenstream:: { DelimSpan ,  Spacing ,  TokenStream ,  TokenTree } ; 
44use  rustc_ast_pretty:: pprust:: token_to_string; 
55use  rustc_data_structures:: fx:: FxHashMap ; 
6- use  rustc_errors:: { PErr ,  PResult } ; 
6+ use  rustc_errors:: { Diagnostic ,   PErr ,  PResult } ; 
77use  rustc_span:: Span ; 
88
99pub ( super )  struct  TokenTreesReader < ' a >  { 
@@ -104,22 +104,7 @@ impl<'a> TokenTreesReader<'a> {
104104        } 
105105
106106        if  let  Some ( ( delim,  _) )  = self . open_braces . last ( )  { 
107-             if  let  Some ( ( _,  open_sp,  close_sp) )  =
108-                 self . matching_delim_spans . iter ( ) . find ( |( d,  open_sp,  close_sp) | { 
109-                     let  sm = self . string_reader . sess . source_map ( ) ; 
110-                     if  let  Some ( close_padding)  = sm. span_to_margin ( * close_sp)  { 
111-                         if  let  Some ( open_padding)  = sm. span_to_margin ( * open_sp)  { 
112-                             return  delim == d && close_padding != open_padding; 
113-                         } 
114-                     } 
115-                     false 
116-                 } ) 
117-             // these are in reverse order as they get inserted on close, but 
118-             { 
119-                 // we want the last open/first close 
120-                 err. span_label ( * open_sp,  "this delimiter might not be properly closed..." ) ; 
121-                 err. span_label ( * close_sp,  "...as it matches this but it has different indentation" ) ; 
122-             } 
107+             self . report_error_prone_delim_block ( * delim,  & mut  err) ; 
123108        } 
124109        err
125110    } 
@@ -157,15 +142,11 @@ impl<'a> TokenTreesReader<'a> {
157142                //only add braces 
158143                if  let  ( Delimiter :: Brace ,  Delimiter :: Brace )  = ( open_brace,  open_delim)  { 
159144                    self . matching_block_spans . push ( ( open_brace_span,  close_brace_span) ) ; 
160-                 } 
161145
162-                 if  self . open_braces . is_empty ( )  { 
163-                     // Clear up these spans to avoid suggesting them as we've found 
164-                     // properly matched delimiters so far for an entire block. 
165-                     self . matching_delim_spans . clear ( ) ; 
166-                 }  else  { 
146+                     // Add all the matching spans, we will sort by span later 
167147                    self . matching_delim_spans . push ( ( open_brace,  open_brace_span,  close_brace_span) ) ; 
168148                } 
149+ 
169150                // Move past the closing delimiter. 
170151                self . token  = self . string_reader . next_token ( ) . 0 ; 
171152            } 
@@ -183,15 +164,12 @@ impl<'a> TokenTreesReader<'a> {
183164                    if  let  Some ( & ( _,  sp) )  = self . open_braces . last ( )  { 
184165                        unclosed_delimiter = Some ( sp) ; 
185166                    } ; 
186-                     let  sm = self . string_reader . sess . source_map ( ) ; 
187-                     if  let  Some ( current_padding)  = sm. span_to_margin ( self . token . span )  { 
188-                         for  ( brace,  brace_span)  in  & self . open_braces  { 
189-                             if  let  Some ( padding)  = sm. span_to_margin ( * brace_span)  { 
190-                                 // high likelihood of these two corresponding 
191-                                 if  current_padding == padding && brace == & close_delim { 
192-                                     candidate = Some ( * brace_span) ; 
193-                                 } 
194-                             } 
167+                     for  ( brace,  brace_span)  in  & self . open_braces  { 
168+                         if  self . same_identation_level ( self . token . span ,  * brace_span) 
169+                             && brace == & close_delim
170+                         { 
171+                             // high likelihood of these two corresponding 
172+                             candidate = Some ( * brace_span) ; 
195173                        } 
196174                    } 
197175                    let  ( tok,  _)  = self . open_braces . pop ( ) . unwrap ( ) ; 
@@ -236,23 +214,68 @@ impl<'a> TokenTreesReader<'a> {
236214        let  mut  err =
237215            self . string_reader . sess . span_diagnostic . struct_span_err ( self . token . span ,  & msg) ; 
238216
239-         // Braces are added at the end, so the last element is the biggest block 
240-         if  let  Some ( parent)  = self . matching_block_spans . last ( )  { 
241-             if  let  Some ( span)  = self . last_delim_empty_block_spans . remove ( & delim)  { 
242-                 // Check if the (empty block) is in the last properly closed block 
243-                 if  ( parent. 0 . to ( parent. 1 ) ) . contains ( span)  { 
244-                     err. span_label ( span,  "block is empty, you might have not meant to close it" ) ; 
245-                 }  else  { 
246-                     err. span_label ( parent. 0 ,  "this opening brace..." ) ; 
247-                     err. span_label ( parent. 1 ,  "...matches this closing brace" ) ; 
217+         self . report_error_prone_delim_block ( delim,  & mut  err) ; 
218+         err. span_label ( self . token . span ,  "unexpected closing delimiter" ) ; 
219+         err
220+     } 
221+ 
222+     fn  same_identation_level ( & self ,  open_sp :  Span ,  close_sp :  Span )  -> bool  { 
223+         let  sm = self . string_reader . sess . source_map ( ) ; 
224+         if  let  ( Some ( open_padding) ,  Some ( close_padding) )  =
225+             ( sm. span_to_margin ( open_sp) ,  sm. span_to_margin ( close_sp) ) 
226+         { 
227+             open_padding == close_padding
228+         }  else  { 
229+             false 
230+         } 
231+     } 
232+ 
233+     fn  report_error_prone_delim_block ( & self ,  delim :  Delimiter ,  err :  & mut  Diagnostic )  { 
234+         let  mut  matched_spans = vec ! [ ] ; 
235+         let  mut  candidate_span = None ; 
236+ 
237+         for  & ( d,  open_sp,  close_sp)  in  & self . matching_delim_spans  { 
238+             if  d == delim { 
239+                 let  block_span = open_sp. with_hi ( close_sp. lo ( ) ) ; 
240+                 let  same_ident = self . same_identation_level ( open_sp,  close_sp) ; 
241+                 matched_spans. push ( ( block_span,  same_ident) ) ; 
242+             } 
243+         } 
244+ 
245+         // sort by `lo`, so the large block spans in the front 
246+         matched_spans. sort_by ( |a,  b| a. 0 . lo ( ) . cmp ( & b. 0 . lo ( ) ) ) ; 
247+ 
248+         // We use larger block whose identation is well to cover those innert blocks 
249+         // O(N^2) here, but we are on error reporting path, so it is fine 
250+         for  i in  0 ..matched_spans. len ( )  { 
251+             let  ( block_span,  same_ident)  = matched_spans[ i] ; 
252+             if  same_ident { 
253+                 for  j in  i + 1 ..matched_spans. len ( )  { 
254+                     let  ( inner_block,  innert_same_ident)  = matched_spans[ j] ; 
255+                     if  block_span. contains ( inner_block)  && !innert_same_ident { 
256+                         matched_spans[ j]  = ( inner_block,  true ) ; 
257+                     } 
248258                } 
249-             }  else  { 
250-                 err. span_label ( parent. 0 ,  "this opening brace..." ) ; 
251-                 err. span_label ( parent. 1 ,  "...matches this closing brace" ) ; 
252259            } 
253260        } 
254261
255-         err. span_label ( self . token . span ,  "unexpected closing delimiter" ) ; 
256-         err
262+         // Find the innermost span candidate for final report 
263+         for  ( block_span,  same_ident)  in  matched_spans. into_iter ( ) . rev ( )  { 
264+             if  !same_ident { 
265+                 candidate_span = Some ( block_span) ; 
266+                 break ; 
267+             } 
268+         } 
269+ 
270+         if  let  Some ( block_span)  = candidate_span { 
271+             err. span_label ( 
272+                 block_span. shrink_to_lo ( ) , 
273+                 "this delimiter might not be properly closed..." , 
274+             ) ; 
275+             err. span_label ( 
276+                 block_span. shrink_to_hi ( ) , 
277+                 "...as it matches this but it has different indentation" , 
278+             ) ; 
279+         } 
257280    } 
258281} 
0 commit comments