1
- use std:: collections:: HashMap ;
1
+ use std:: collections:: { HashMap , HashSet } ;
2
2
use std:: ops:: Range ;
3
3
4
4
use proc_macro2:: { Group , Ident , Span , TokenStream , TokenTree } ;
@@ -9,9 +9,10 @@ use syn::spanned::Spanned as _;
9
9
use syn:: {
10
10
parse2, parse_quote, token, AttrStyle , Attribute , Block , Expr , ExprArray , ExprBlock , ExprField ,
11
11
ExprLit , ExprRange , ExprTuple , Fields , FieldsNamed , FieldsUnnamed , GenericArgument ,
12
- GenericParam , Generics , ImplItem , Index , Item , Lit , LitInt , Macro , MacroDelimiter , Member ,
13
- Meta , Pat , Path , PathArguments , PathSegment , PredicateType , QSelf , RangeLimits , ReturnType ,
14
- Stmt , Token , Type , TypeMacro , TypeParamBound , TypePath , TypeTuple , Variant , WherePredicate ,
12
+ GenericParam , Generics , ImplItem , Index , Item , Label , Lit , LitInt , Macro , MacroDelimiter ,
13
+ Member , Meta , Pat , Path , PathArguments , PathSegment , PredicateType , QSelf , RangeLimits ,
14
+ ReturnType , Stmt , Token , Type , TypeMacro , TypeParamBound , TypePath , TypeTuple , Variant ,
15
+ WherePredicate ,
15
16
} ;
16
17
17
18
use crate :: constant:: { evaluate_bool, evaluate_range, evaluate_usize} ;
@@ -42,6 +43,33 @@ impl Typle {
42
43
#[ derive( Default ) ]
43
44
pub struct BlockState {
44
45
unlabelled_control_flow : bool ,
46
+ labelled_continue : HashSet < Ident > ,
47
+ }
48
+
49
+ impl BlockState {
50
+ // Propagate the labels from an inner loop into the state for this loop.
51
+ // We exclude any unlabelled_control_flow as it is contained by the inner
52
+ // loop. We also exclude any label attached to the inner loop.
53
+ fn propagate ( & mut self , inner : Self , label : Option < & Label > ) {
54
+ for ident in inner. labelled_continue {
55
+ if let Some ( label) = label {
56
+ if label. name . ident == ident {
57
+ continue ;
58
+ }
59
+ }
60
+ self . labelled_continue . insert ( ident) ;
61
+ }
62
+ }
63
+
64
+ // Return whether this loop has any labelled continue that refers to this loop's label.
65
+ fn has_labelled_continue < ' a > ( & self , label : Option < & ' a Label > ) -> Option < & ' a Label > {
66
+ if let Some ( label) = label {
67
+ if self . labelled_continue . contains ( & label. name . ident ) {
68
+ return Some ( label) ;
69
+ }
70
+ }
71
+ None
72
+ }
45
73
}
46
74
47
75
#[ derive( Clone ) ]
@@ -307,7 +335,15 @@ impl<'a> SpecificContext<'a> {
307
335
}
308
336
Expr :: Continue ( cont) => {
309
337
self . replace_attrs ( & mut cont. attrs ) ;
310
- if cont. label . is_none ( ) {
338
+ match & cont. label {
339
+ Some ( lt) => {
340
+ state. labelled_continue . insert ( lt. ident . clone ( ) ) ;
341
+ }
342
+ None => {
343
+ state. unlabelled_control_flow = true ;
344
+ }
345
+ }
346
+ {
311
347
state. unlabelled_control_flow = true ;
312
348
}
313
349
}
@@ -359,18 +395,46 @@ impl<'a> SpecificContext<'a> {
359
395
let mut context = self . clone ( ) ;
360
396
let mut stmts = Vec :: new ( ) ;
361
397
context. constants . insert ( pat_ident. clone ( ) , 0 ) ;
362
- let mut unlabelled_control_flow = false ;
398
+ let mut check_for_break = false ;
363
399
for index in start..end {
364
400
context. constants . get_mut ( & pat_ident) . map ( |v| * v = index) ;
365
401
let mut block = for_loop. body . clone ( ) ;
366
- let mut state = BlockState :: default ( ) ;
367
- context. replace_block ( & mut block, & mut state ) ;
402
+ let mut inner_state = BlockState :: default ( ) ;
403
+ context. replace_block ( & mut block, & mut inner_state ) ;
368
404
if block. stmts . is_empty ( ) {
369
405
continue ;
370
406
}
371
- if state. unlabelled_control_flow {
372
- if !unlabelled_control_flow {
373
- unlabelled_control_flow = true ;
407
+ if let Some ( label) =
408
+ inner_state. has_labelled_continue ( for_loop. label . as_ref ( ) )
409
+ {
410
+ if !check_for_break {
411
+ check_for_break = true ;
412
+ stmts. push ( parse_quote ! {
413
+ let mut _typle_break = false ;
414
+ } ) ;
415
+ }
416
+ // If a labelled `continue` occurs inside the block then control
417
+ // goes to the start of the loop with `_typle_break = true`
418
+ // which causes the loop to be exited with `_typle_break = false`.
419
+ // This label shadows the label on the outer block. If there is
420
+ // a labelled break as well, then it will break from this loop
421
+ // without setting _typle_break back to false.
422
+ let stmt = parse_quote ! {
423
+ if ! _typle_break {
424
+ #label loop {
425
+ if _typle_break {
426
+ _typle_break = false ;
427
+ break ;
428
+ }
429
+ _typle_break = true ;
430
+ #block
431
+ }
432
+ }
433
+ } ;
434
+ stmts. push ( stmt) ;
435
+ } else if inner_state. unlabelled_control_flow {
436
+ if !check_for_break {
437
+ check_for_break = true ;
374
438
stmts. push ( parse_quote ! {
375
439
let mut _typle_break = false ;
376
440
} ) ;
@@ -395,7 +459,7 @@ impl<'a> SpecificContext<'a> {
395
459
} ;
396
460
stmts. push ( stmt) ;
397
461
} else {
398
- if unlabelled_control_flow {
462
+ if check_for_break {
399
463
// If this block does not contain a break or continue, but
400
464
// previous blocks did we need to check for the `break`
401
465
// condition before running this block.
@@ -414,6 +478,7 @@ impl<'a> SpecificContext<'a> {
414
478
) ) ;
415
479
}
416
480
}
481
+ state. propagate ( inner_state, for_loop. label . as_ref ( ) ) ;
417
482
}
418
483
stmts. push ( Stmt :: Expr (
419
484
Expr :: Tuple ( ExprTuple {
@@ -437,8 +502,9 @@ impl<'a> SpecificContext<'a> {
437
502
}
438
503
// Otherwise it is a standard for loop
439
504
self . replace_pat ( & mut for_loop. pat ) ;
440
- let mut state = BlockState :: default ( ) ;
441
- self . replace_block ( & mut for_loop. body , & mut state) ;
505
+ let mut inner_state = BlockState :: default ( ) ;
506
+ self . replace_block ( & mut for_loop. body , & mut inner_state) ;
507
+ state. propagate ( inner_state, for_loop. label . as_ref ( ) ) ;
442
508
}
443
509
Expr :: Group ( group) => {
444
510
self . replace_attrs ( & mut group. attrs ) ;
@@ -525,8 +591,9 @@ impl<'a> SpecificContext<'a> {
525
591
}
526
592
Expr :: Loop ( r#loop) => {
527
593
self . replace_attrs ( & mut r#loop. attrs ) ;
528
- let mut state = BlockState :: default ( ) ;
529
- self . replace_block ( & mut r#loop. body , & mut state) ;
594
+ let mut inner_state = BlockState :: default ( ) ;
595
+ self . replace_block ( & mut r#loop. body , & mut inner_state) ;
596
+ state. propagate ( inner_state, r#loop. label . as_ref ( ) ) ;
530
597
}
531
598
Expr :: Macro ( r#macro) => {
532
599
self . replace_attrs ( & mut r#macro. attrs ) ;
@@ -774,8 +841,9 @@ impl<'a> SpecificContext<'a> {
774
841
Expr :: While ( r#while) => {
775
842
self . replace_attrs ( & mut r#while. attrs ) ;
776
843
self . replace_expr ( & mut r#while. cond , state) ;
777
- let mut state = BlockState :: default ( ) ;
778
- self . replace_block ( & mut r#while. body , & mut state) ;
844
+ let mut inner_state = BlockState :: default ( ) ;
845
+ self . replace_block ( & mut r#while. body , & mut inner_state) ;
846
+ state. propagate ( inner_state, r#while. label . as_ref ( ) ) ;
779
847
}
780
848
Expr :: Yield ( r#yield) => {
781
849
self . replace_attrs ( & mut r#yield. attrs ) ;
0 commit comments