@@ -946,9 +946,10 @@ impl FunctionLike for SetterProp {
946946enum BlockContext {
947947 // In the root of a function scope
948948 Function { id : u32 , binds_this : bool } ,
949- FunctionRoot ,
950- // In the root of the module scope
951- Module ,
949+ // A placeholder for identify anonymous blocks
950+ // If we have Block->Block then we are in an anonymous block
951+ // If we have Function->Block or ControlFlow->Block then we are just in a function root
952+ Block ,
952953 // In some kind of control flow
953954 ControlFlow { is_try : bool } ,
954955}
@@ -1004,12 +1005,17 @@ mod analyzer_state {
10041005 /// Returns true if we are currently in a block scope that isn't at the root of a function
10051006 /// or a module.
10061007 pub ( super ) fn is_in_nested_block_scope ( & self ) -> bool {
1007- match self . state . block_context_stack . last ( ) . unwrap ( ) {
1008- BlockContext :: Module
1009- | BlockContext :: FunctionRoot
1010- | BlockContext :: Function { .. } => false ,
1008+ match & self . state . block_context_stack
1009+ [ self . state . block_context_stack . len ( ) . saturating_sub ( 2 ) ..]
1010+ {
1011+ [ BlockContext :: Block ] | [ BlockContext :: Function { .. } , BlockContext :: Block ] => {
1012+ false
1013+ }
1014+ [ ] => {
1015+ unreachable ! ( )
1016+ }
10111017
1012- BlockContext :: ControlFlow { .. } => true ,
1018+ _ => true ,
10131019 }
10141020 }
10151021
@@ -1110,7 +1116,7 @@ mod analyzer_state {
11101116 let fn_id = function. span ( ) . lo . 0 ;
11111117 let prev_return_values = self . state . cur_fn_return_values . replace ( vec ! [ ] ) ;
11121118
1113- self . enter_block (
1119+ self . with_block (
11141120 BlockContext :: Function {
11151121 id : fn_id,
11161122 binds_this : function. binds_this ( ) ,
@@ -1180,14 +1186,25 @@ mod analyzer_state {
11801186 func : impl FnOnce ( & mut Self ) -> T ,
11811187 ) -> ( T , bool ) {
11821188 let prev_early_return_stack = take ( & mut self . state . early_return_stack ) ;
1183- self . state . block_context_stack . push ( block_kind) ;
1184- let result = func ( self ) ;
1189+ let result = self . with_block ( block_kind, func) ;
11851190 let always_returns = self . end_early_return_block ( ) ;
11861191 self . state . early_return_stack = prev_early_return_stack;
1192+ ( result, always_returns)
1193+ }
1194+
1195+ /// Pushes a block onto the stack without performing early return logic.
1196+ pub ( super ) fn with_block < T > (
1197+ & mut self ,
1198+ block_kind : BlockContext ,
1199+ func : impl FnOnce ( & mut Self ) -> T ,
1200+ ) -> T {
1201+ self . state . block_context_stack . push ( block_kind) ;
1202+ let result = func ( self ) ;
11871203 let old = self . state . block_context_stack . pop ( ) ;
11881204 debug_assert_eq ! ( old, Some ( block_kind) ) ;
1189- ( result, always_returns )
1205+ result
11901206 }
1207+
11911208 /// Ends a conditional block. All early returns are integrated into the
11921209 /// effects. Returns true if the whole block always early returns.
11931210 fn end_early_return_block ( & mut self ) -> bool {
@@ -2449,7 +2466,7 @@ impl VisitAstPath for Analyzer<'_> {
24492466 ast_path : & mut AstNodePath < AstParentNodeRef < ' r > > ,
24502467 ) {
24512468 self . effects = take ( & mut self . data . effects ) ;
2452- self . enter_block ( BlockContext :: Module , |this| {
2469+ self . enter_block ( BlockContext :: Block , |this| {
24532470 program. visit_children_with_ast_path ( this, ast_path) ;
24542471 } ) ;
24552472 self . effects . append ( & mut self . hoisted_effects ) ;
@@ -2664,10 +2681,9 @@ impl VisitAstPath for Analyzer<'_> {
26642681 let mut effects = take ( & mut self . effects ) ;
26652682 let hoisted_effects = take ( & mut self . hoisted_effects ) ;
26662683
2667- let ( _, returns_unconditionally) =
2668- self . enter_block ( BlockContext :: FunctionRoot , |this| {
2669- n. visit_children_with_ast_path ( this, ast_path) ;
2670- } ) ;
2684+ let ( _, returns_unconditionally) = self . enter_block ( BlockContext :: Block , |this| {
2685+ n. visit_children_with_ast_path ( this, ast_path) ;
2686+ } ) ;
26712687 // By handling this logic here instead of in enter_fn, we naturally skip it
26722688 // for arrow functions with single expression bodies, since they just don't hit this
26732689 // path.
@@ -2679,29 +2695,20 @@ impl VisitAstPath for Analyzer<'_> {
26792695 self . hoisted_effects = hoisted_effects;
26802696 self . effects = effects;
26812697 }
2682- BlockContext :: ControlFlow { .. }
2683- | BlockContext :: Module
2684- | BlockContext :: FunctionRoot => {
2685- // A block is anonymous if its parent is also a block (rather than a
2686- // loop/function/if-stmt)
2687- let is_anonymous_block = matches ! (
2688- ast_path. get( ast_path. len( ) - 2 ) ,
2689- Some ( AstParentNodeRef :: BlockStmt ( _, BlockStmtField :: Stmts ( _) ) )
2690- ) ;
2691-
2692- if is_anonymous_block {
2693- // Handle anonymous block statement
2694- // e.g., enter a new control flow context and because it is 'unconditiona' we
2695- // need to propagate early returns
2696- let ( _, returns_early) = self . enter_control_flow ( |this| {
2697- n. visit_children_with_ast_path ( this, ast_path) ;
2698- } ) ;
2699- if returns_early {
2700- self . add_early_return_always ( ast_path) ;
2701- }
2702- } else {
2703- // Regular block (part of if/loop/function/etc)
2704- n. visit_children_with_ast_path ( self , ast_path) ;
2698+ BlockContext :: ControlFlow { .. } => {
2699+ self . with_block ( BlockContext :: Block , |this| {
2700+ n. visit_children_with_ast_path ( this, ast_path)
2701+ } ) ;
2702+ }
2703+ BlockContext :: Block => {
2704+ // Handle anonymous block statement
2705+ // e.g., enter a new control flow context and because it is 'unconditiona' we
2706+ // need to propagate early returns
2707+ let ( _, returns_early) = self . enter_control_flow ( |this| {
2708+ n. visit_children_with_ast_path ( this, ast_path) ;
2709+ } ) ;
2710+ if returns_early {
2711+ self . add_early_return_always ( ast_path) ;
27052712 }
27062713 }
27072714 }
0 commit comments