@@ -28,6 +28,7 @@ use qsc_fir::fir::{
2828} ; 
2929use  qsc_fir:: ty:: Ty ; 
3030use  rand:: { rngs:: StdRng ,  SeedableRng } ; 
31+ use  std:: ops; 
3132use  std:: { 
3233    cell:: RefCell , 
3334    fmt:: { self ,  Display ,  Formatter } , 
@@ -172,6 +173,26 @@ impl Display for Spec {
172173    } 
173174} 
174175
176+ /// Utility function to identify a subset of a control flow graph corresponding to a given 
177+ /// range. 
178+ #[ must_use]  
179+ pub  fn  sub_cfg ( cfg :  & Rc < [ CfgNode ] > ,  range :  ops:: Range < usize > )  -> Rc < [ CfgNode ] >  { 
180+     let  start:  u32  = range
181+         . start 
182+         . try_into ( ) 
183+         . expect ( "cfg ranges should fit into u32" ) ; 
184+     cfg[ range] 
185+         . iter ( ) 
186+         . map ( |node| match  node { 
187+             CfgNode :: Jump ( idx)  => CfgNode :: Jump ( idx - start) , 
188+             CfgNode :: JumpIf ( idx)  => CfgNode :: JumpIf ( idx - start) , 
189+             CfgNode :: JumpIfNot ( idx)  => CfgNode :: JumpIfNot ( idx - start) , 
190+             _ => * node, 
191+         } ) 
192+         . collect :: < Vec < _ > > ( ) 
193+         . into ( ) 
194+ } 
195+ 
175196/// Evaluates the given code with the given context. 
176197/// # Errors 
177198/// Returns the first error encountered during execution. 
@@ -480,24 +501,20 @@ impl State {
480501            let  cfg = self 
481502                . cfg_stack 
482503                . last ( ) 
483-                 . expect ( "should have at least one stack frame" ) 
484-                 . clone ( ) ; 
485-             let  res = match  cfg
486-                 . get ( self . idx  as  usize ) 
487-                 . expect ( "should have next node in CFG" ) 
488-             { 
489-                 CfgNode :: Bind ( pat)  => { 
504+                 . expect ( "should have at least one stack frame" ) ; 
505+             let  res = match  cfg. get ( self . idx  as  usize )  { 
506+                 Some ( CfgNode :: Bind ( pat) )  => { 
490507                    self . idx  += 1 ; 
491508                    self . eval_bind ( env,  globals,  * pat) ; 
492509                    continue ; 
493510                } 
494-                 CfgNode :: Expr ( expr)  => { 
511+                 Some ( CfgNode :: Expr ( expr) )  => { 
495512                    self . idx  += 1 ; 
496513                    self . eval_expr ( env,  sim,  globals,  out,  * expr) 
497514                        . map_err ( |e| ( e,  self . get_stack_frames ( ) ) ) ?; 
498515                    continue ; 
499516                } 
500-                 CfgNode :: Stmt ( stmt)  => { 
517+                 Some ( CfgNode :: Stmt ( stmt) )  => { 
501518                    self . idx  += 1 ; 
502519                    self . current_span  = globals. get_stmt ( ( self . package ,  * stmt) . into ( ) ) . span ; 
503520
@@ -521,11 +538,11 @@ impl State {
521538                        } 
522539                    } 
523540                } 
524-                 CfgNode :: Jump ( idx)  => { 
541+                 Some ( CfgNode :: Jump ( idx) )  => { 
525542                    self . idx  = * idx; 
526543                    continue ; 
527544                } 
528-                 CfgNode :: JumpIf ( idx)  => { 
545+                 Some ( CfgNode :: JumpIf ( idx) )  => { 
529546                    let  cond = self . curr_val  == Some ( Value :: Bool ( true ) ) ; 
530547                    if  cond { 
531548                        self . idx  = * idx; 
@@ -534,7 +551,7 @@ impl State {
534551                    } 
535552                    continue ; 
536553                } 
537-                 CfgNode :: JumpIfNot ( idx)  => { 
554+                 Some ( CfgNode :: JumpIfNot ( idx) )  => { 
538555                    let  cond = self . curr_val  == Some ( Value :: Bool ( true ) ) ; 
539556                    if  cond { 
540557                        self . idx  += 1 ; 
@@ -543,21 +560,30 @@ impl State {
543560                    } 
544561                    continue ; 
545562                } 
546-                 CfgNode :: Store  => { 
563+                 Some ( CfgNode :: Store )  => { 
547564                    self . push_val ( ) ; 
548565                    self . idx  += 1 ; 
549566                    continue ; 
550567                } 
551-                 CfgNode :: Unit  => { 
568+                 Some ( CfgNode :: Unit )  => { 
552569                    self . idx  += 1 ; 
553570                    self . set_curr_val ( Value :: unit ( ) ) ; 
554571                    continue ; 
555572                } 
556-                 CfgNode :: Ret  => { 
573+                 Some ( CfgNode :: Ret )  => { 
557574                    self . leave_frame ( ) ; 
558575                    env. leave_scope ( ) ; 
559576                    continue ; 
560577                } 
578+                 None  => { 
579+                     // We have reached the end of the current cfg without reaching an explicit return node, 
580+                     // usually indicating the partial execution of a single sub-expression. 
581+                     // This means we should leave the current frame but not the current environment scope, 
582+                     // so bound variables are still accessible after completion. 
583+                     self . leave_frame ( ) ; 
584+                     assert ! ( self . cfg_stack. is_empty( ) ) ; 
585+                     continue ; 
586+                 } 
561587            } ; 
562588
563589            if  let  StepResult :: Return ( _)  = res { 
0 commit comments