1- use std:: collections:: HashMap ;
1+ use std:: collections:: { HashMap , HashSet } ;
22use std:: ops:: Range ;
33
44use proc_macro2:: { Group , Ident , Span , TokenStream , TokenTree } ;
@@ -9,9 +9,10 @@ use syn::spanned::Spanned as _;
99use syn:: {
1010 parse2, parse_quote, token, AttrStyle , Attribute , Block , Expr , ExprArray , ExprBlock , ExprField ,
1111 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 ,
1516} ;
1617
1718use crate :: constant:: { evaluate_bool, evaluate_range, evaluate_usize} ;
@@ -42,6 +43,33 @@ impl Typle {
4243#[ derive( Default ) ]
4344pub struct BlockState {
4445 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+ }
4573}
4674
4775#[ derive( Clone ) ]
@@ -307,7 +335,15 @@ impl<'a> SpecificContext<'a> {
307335 }
308336 Expr :: Continue ( cont) => {
309337 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+ {
311347 state. unlabelled_control_flow = true ;
312348 }
313349 }
@@ -359,18 +395,46 @@ impl<'a> SpecificContext<'a> {
359395 let mut context = self . clone ( ) ;
360396 let mut stmts = Vec :: new ( ) ;
361397 context. constants . insert ( pat_ident. clone ( ) , 0 ) ;
362- let mut unlabelled_control_flow = false ;
398+ let mut check_for_break = false ;
363399 for index in start..end {
364400 context. constants . get_mut ( & pat_ident) . map ( |v| * v = index) ;
365401 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 ) ;
368404 if block. stmts . is_empty ( ) {
369405 continue ;
370406 }
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 ;
374438 stmts. push ( parse_quote ! {
375439 let mut _typle_break = false ;
376440 } ) ;
@@ -395,7 +459,7 @@ impl<'a> SpecificContext<'a> {
395459 } ;
396460 stmts. push ( stmt) ;
397461 } else {
398- if unlabelled_control_flow {
462+ if check_for_break {
399463 // If this block does not contain a break or continue, but
400464 // previous blocks did we need to check for the `break`
401465 // condition before running this block.
@@ -414,6 +478,7 @@ impl<'a> SpecificContext<'a> {
414478 ) ) ;
415479 }
416480 }
481+ state. propagate ( inner_state, for_loop. label . as_ref ( ) ) ;
417482 }
418483 stmts. push ( Stmt :: Expr (
419484 Expr :: Tuple ( ExprTuple {
@@ -437,8 +502,9 @@ impl<'a> SpecificContext<'a> {
437502 }
438503 // Otherwise it is a standard for loop
439504 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 ( ) ) ;
442508 }
443509 Expr :: Group ( group) => {
444510 self . replace_attrs ( & mut group. attrs ) ;
@@ -525,8 +591,9 @@ impl<'a> SpecificContext<'a> {
525591 }
526592 Expr :: Loop ( r#loop) => {
527593 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 ( ) ) ;
530597 }
531598 Expr :: Macro ( r#macro) => {
532599 self . replace_attrs ( & mut r#macro. attrs ) ;
@@ -774,8 +841,9 @@ impl<'a> SpecificContext<'a> {
774841 Expr :: While ( r#while) => {
775842 self . replace_attrs ( & mut r#while. attrs ) ;
776843 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 ( ) ) ;
779847 }
780848 Expr :: Yield ( r#yield) => {
781849 self . replace_attrs ( & mut r#yield. attrs ) ;
0 commit comments