@@ -226,6 +226,15 @@ pub(crate) enum ErrorMatchKind {
226
226
Code ( Spanned < String > ) ,
227
227
}
228
228
229
+ impl ErrorMatchKind {
230
+ fn span ( & self ) -> & Span {
231
+ match self {
232
+ Self :: Pattern { pattern, .. } => & pattern. span ,
233
+ Self :: Code ( code) => & code. span ,
234
+ }
235
+ }
236
+ }
237
+
229
238
#[ derive( Debug , Clone ) ]
230
239
pub ( crate ) struct ErrorMatch {
231
240
pub ( crate ) kind : ErrorMatchKind ,
@@ -254,6 +263,21 @@ impl Condition {
254
263
}
255
264
}
256
265
266
+ enum ParsePatternResult {
267
+ Other ,
268
+ ErrorAbove {
269
+ match_line : NonZeroUsize ,
270
+ } ,
271
+ ErrorBelow {
272
+ span : Span ,
273
+ match_line : NonZeroUsize ,
274
+ } ,
275
+ Fallthrough {
276
+ span : Span ,
277
+ idx : usize ,
278
+ } ,
279
+ }
280
+
257
281
impl Comments {
258
282
pub ( crate ) fn parse_file (
259
283
comments : Comments ,
@@ -279,6 +303,7 @@ impl Comments {
279
303
280
304
let defaults = std:: mem:: take ( parser. comments . revisioned . get_mut ( & [ ] [ ..] ) . unwrap ( ) ) ;
281
305
306
+ let mut delayed_fallthrough = Vec :: new ( ) ;
282
307
let mut fallthrough_to = None ; // The line that a `|` will refer to.
283
308
let mut last_line = 0 ;
284
309
for ( l, line) in content. as_ref ( ) . lines ( ) . enumerate ( ) {
@@ -291,8 +316,37 @@ impl Comments {
291
316
col_start : NonZeroUsize :: new ( 1 ) . unwrap ( ) ,
292
317
col_end : NonZeroUsize :: new ( line. chars ( ) . count ( ) + 1 ) . unwrap ( ) ,
293
318
} ;
294
- match parser. parse_checked_line ( & mut fallthrough_to, Spanned :: new ( line, span) ) {
295
- Ok ( ( ) ) => { }
319
+ match parser. parse_checked_line ( fallthrough_to, Spanned :: new ( line, span) ) {
320
+ Ok ( ParsePatternResult :: Other ) => {
321
+ fallthrough_to = None ;
322
+ }
323
+ Ok ( ParsePatternResult :: ErrorAbove { match_line } ) => {
324
+ fallthrough_to = Some ( match_line) ;
325
+ }
326
+ Ok ( ParsePatternResult :: Fallthrough { span, idx } ) => {
327
+ delayed_fallthrough. push ( ( span, l, idx) ) ;
328
+ }
329
+ Ok ( ParsePatternResult :: ErrorBelow { span, match_line } ) => {
330
+ if fallthrough_to. is_some ( ) {
331
+ parser. error (
332
+ span,
333
+ "`//~v` comment immediately following a `//~^` comment chain" ,
334
+ ) ;
335
+ }
336
+
337
+ for ( span, line, idx) in delayed_fallthrough. drain ( ..) {
338
+ if let Some ( rev) = parser
339
+ . comments
340
+ . revisioned
341
+ . values_mut ( )
342
+ . find ( |rev| rev. error_matches [ idx] . kind . span ( ) . line_start == line)
343
+ {
344
+ rev. error_matches [ idx] . line = match_line;
345
+ } else {
346
+ parser. error ( span, "`//~|` comment not attached to anchoring matcher" ) ;
347
+ }
348
+ }
349
+ }
296
350
Err ( e) => parser. error ( e. span , format ! ( "Comment is not utf8: {:?}" , e. content) ) ,
297
351
}
298
352
}
@@ -337,6 +391,10 @@ impl Comments {
337
391
}
338
392
}
339
393
394
+ for ( span, ..) in delayed_fallthrough {
395
+ parser. error ( span, "`//~|` comment not attached to anchoring matcher" ) ;
396
+ }
397
+
340
398
let Revisioned {
341
399
span,
342
400
ignore,
@@ -397,18 +455,18 @@ impl Comments {
397
455
impl CommentParser < Comments > {
398
456
fn parse_checked_line (
399
457
& mut self ,
400
- fallthrough_to : & mut Option < NonZeroUsize > ,
458
+ fallthrough_to : Option < NonZeroUsize > ,
401
459
line : Spanned < & [ u8 ] > ,
402
- ) -> std:: result:: Result < ( ) , Spanned < Utf8Error > > {
460
+ ) -> std:: result:: Result < ParsePatternResult , Spanned < Utf8Error > > {
461
+ let mut res = ParsePatternResult :: Other ;
403
462
if let Some ( command) = line. strip_prefix ( b"//@" ) {
404
463
self . parse_command ( command. to_str ( ) ?. trim ( ) )
405
464
} else if let Some ( ( _, pattern) ) = line. split_once_str ( "//~" ) {
406
465
let ( revisions, pattern) = self . parse_revisions ( pattern. to_str ( ) ?) ;
407
466
self . revisioned ( revisions, |this| {
408
- this. parse_pattern ( pattern, fallthrough_to)
467
+ res = this. parse_pattern ( pattern, fallthrough_to) ;
409
468
} )
410
469
} else {
411
- * fallthrough_to = None ;
412
470
for pos in line. clone ( ) . find_iter ( "//" ) {
413
471
let ( _, rest) = line. clone ( ) . to_str ( ) ?. split_at ( pos + 2 ) ;
414
472
for rest in std:: iter:: once ( rest. clone ( ) ) . chain ( rest. strip_prefix ( " " ) ) {
@@ -448,7 +506,7 @@ impl CommentParser<Comments> {
448
506
}
449
507
}
450
508
}
451
- Ok ( ( ) )
509
+ Ok ( res )
452
510
}
453
511
}
454
512
@@ -835,15 +893,27 @@ impl CommentParser<&mut Revisioned> {
835
893
// (\[[a-z]+(,[a-z]+)*\])?
836
894
// (?P<offset>\||[\^]+)? *
837
895
// ((?P<level>ERROR|HELP|WARN|NOTE): (?P<text>.*))|(?P<code>[a-z0-9_:]+)
838
- fn parse_pattern ( & mut self , pattern : Spanned < & str > , fallthrough_to : & mut Option < NonZeroUsize > ) {
896
+ fn parse_pattern (
897
+ & mut self ,
898
+ pattern : Spanned < & str > ,
899
+ fallthrough_to : Option < NonZeroUsize > ,
900
+ ) -> ParsePatternResult {
839
901
let c = pattern. chars ( ) . next ( ) ;
902
+ let mut res = ParsePatternResult :: Other ;
903
+
840
904
let ( match_line, pattern) = match c {
841
905
Some ( Spanned { content : '|' , span } ) => (
842
906
match fallthrough_to {
843
- Some ( fallthrough) => * fallthrough,
907
+ Some ( match_line) => {
908
+ res = ParsePatternResult :: ErrorAbove { match_line } ;
909
+ match_line
910
+ }
844
911
None => {
845
- self . error ( span, "`//~|` pattern without preceding line" ) ;
846
- return ;
912
+ res = ParsePatternResult :: Fallthrough {
913
+ span,
914
+ idx : self . error_matches . len ( ) ,
915
+ } ;
916
+ pattern. span . line_start
847
917
}
848
918
} ,
849
919
pattern. split_at ( 1 ) . 1 ,
@@ -862,14 +932,19 @@ impl CommentParser<&mut Revisioned> {
862
932
{
863
933
// lines are one-indexed, so a target line of 0 is invalid, but also
864
934
// prevented via `NonZeroUsize`
865
- Some ( match_line) => ( match_line, pattern. split_at ( offset) . 1 ) ,
935
+ Some ( match_line) => {
936
+ res = ParsePatternResult :: ErrorAbove { match_line } ;
937
+ ( match_line, pattern. split_at ( offset) . 1 )
938
+ }
866
939
_ => {
867
940
self . error ( pattern. span ( ) , format ! (
868
941
"//~^ pattern is trying to refer to {} lines above, but there are only {} lines above" ,
869
942
offset,
870
943
pattern. line( ) . get( ) - 1 ,
871
944
) ) ;
872
- return ;
945
+ return ParsePatternResult :: ErrorAbove {
946
+ match_line : pattern. span ( ) . line_start ,
947
+ } ;
873
948
}
874
949
}
875
950
}
@@ -885,22 +960,31 @@ impl CommentParser<&mut Revisioned> {
885
960
. checked_add ( offset)
886
961
. and_then ( NonZeroUsize :: new)
887
962
{
888
- Some ( match_line) => ( match_line, pattern. split_at ( offset) . 1 ) ,
963
+ Some ( match_line) => {
964
+ res = ParsePatternResult :: ErrorBelow {
965
+ span : pattern. span ( ) ,
966
+ match_line,
967
+ } ;
968
+ ( match_line, pattern. split_at ( offset) . 1 )
969
+ }
889
970
_ => {
890
971
// The line count of the file is not yet known so we can only check
891
972
// if the resulting line is in the range of a usize.
892
973
self . error ( pattern. span ( ) , format ! (
893
974
"//~v pattern is trying to refer to {} lines below, which is more than ui_test can count" ,
894
975
offset,
895
976
) ) ;
896
- return ;
977
+ return ParsePatternResult :: ErrorBelow {
978
+ span : pattern. span ( ) ,
979
+ match_line : pattern. span ( ) . line_start ,
980
+ } ;
897
981
}
898
982
}
899
983
}
900
984
Some ( _) => ( pattern. span ( ) . line_start , pattern) ,
901
985
None => {
902
986
self . error ( pattern. span ( ) , "no pattern specified" ) ;
903
- return ;
987
+ return res ;
904
988
}
905
989
} ;
906
990
@@ -916,7 +1000,7 @@ impl CommentParser<&mut Revisioned> {
916
1000
Ok ( level) => level,
917
1001
Err ( msg) => {
918
1002
self . error ( level. span ( ) , msg) ;
919
- return ;
1003
+ return res ;
920
1004
}
921
1005
} ;
922
1006
@@ -933,13 +1017,13 @@ impl CommentParser<&mut Revisioned> {
933
1017
} else if ( * level_or_code) . parse :: < Level > ( ) . is_ok ( ) {
934
1018
// Shouldn't conflict with any real diagnostic code
935
1019
self . error ( level_or_code. span ( ) , "no `:` after level found" ) ;
936
- return ;
1020
+ return res ;
937
1021
} else if !pattern. trim_start ( ) . is_empty ( ) {
938
1022
self . error (
939
1023
pattern. span ( ) ,
940
1024
format ! ( "text found after error code `{}`" , * level_or_code) ,
941
1025
) ;
942
- return ;
1026
+ return res ;
943
1027
} else {
944
1028
self . error_matches . push ( ErrorMatch {
945
1029
kind : ErrorMatchKind :: Code ( Spanned :: new (
@@ -950,7 +1034,7 @@ impl CommentParser<&mut Revisioned> {
950
1034
} ) ;
951
1035
} ;
952
1036
953
- * fallthrough_to = Some ( match_line ) ;
1037
+ res
954
1038
}
955
1039
}
956
1040
0 commit comments