@@ -937,19 +937,25 @@ mod analyzer_state {
937937
938938 /// Runs `func` with the current function identifier and return values initialized for the
939939 /// block.
940- pub ( super ) fn enter_fn (
941- & mut self ,
942- fn_id : u32 ,
943- initial_return_values : Vec < JsValue > ,
944- func : impl FnOnce ( & mut Self ) ,
945- ) -> JsValue {
940+ pub ( super ) fn enter_fn ( & mut self , fn_id : u32 , func : impl FnOnce ( & mut Self ) ) -> JsValue {
946941 let prev_fn_id = self . state . cur_fn_ident . replace ( fn_id) ;
947-
948- let old_return_values = self
949- . state
950- . cur_fn_return_values
951- . replace ( initial_return_values) ;
942+ let old_return_values = self . state . cur_fn_return_values . replace ( vec ! [ ] ) ;
943+ let early_return_stack = take ( & mut self . early_return_stack ) ;
944+ let mut effects = take ( & mut self . effects ) ;
945+ let hoisted_effects = take ( & mut self . hoisted_effects ) ;
952946 func ( self ) ;
947+ if !self . end_early_return_block ( ) {
948+ // If the block doesn't end in a return there is an implicit `undefined` return
949+ self . get_mut_cur_fn_return_values ( )
950+ . unwrap ( )
951+ . push ( JsValue :: Constant ( ConstantValue :: Undefined ) )
952+ }
953+ self . effects . append ( & mut self . hoisted_effects ) ;
954+ effects. append ( & mut self . effects ) ;
955+ self . hoisted_effects = hoisted_effects;
956+ self . effects = effects;
957+ self . early_return_stack = early_return_stack;
958+
953959 let return_values = self . take_return_values ( ) ;
954960 self . state . cur_fn_ident = prev_fn_id;
955961 self . state . cur_fn_return_values = old_return_values;
@@ -1672,14 +1678,10 @@ impl VisitAstPath for Analyzer<'_> {
16721678 decl : & ' ast FnDecl ,
16731679 ast_path : & mut AstNodePath < AstParentNodeRef < ' r > > ,
16741680 ) {
1675- let fn_value = self . enter_fn (
1676- decl. function . span . lo . 0 ,
1677- get_fn_init_return_vals ( decl. function . body . as_ref ( ) ) ,
1678- |this| {
1679- decl. visit_children_with_ast_path ( this, ast_path) ;
1680- this. hoisted_effects . append ( & mut this. effects ) ;
1681- } ,
1682- ) ;
1681+ let fn_value = self . enter_fn ( decl. function . span . lo . 0 , |this| {
1682+ decl. visit_children_with_ast_path ( this, ast_path) ;
1683+ this. hoisted_effects . append ( & mut this. effects ) ;
1684+ } ) ;
16831685 self . add_value ( decl. ident . to_id ( ) , fn_value) ;
16841686 }
16851687
@@ -1688,13 +1690,9 @@ impl VisitAstPath for Analyzer<'_> {
16881690 expr : & ' ast FnExpr ,
16891691 ast_path : & mut AstNodePath < AstParentNodeRef < ' r > > ,
16901692 ) {
1691- let fn_value = self . enter_fn (
1692- expr. function . span . lo . 0 ,
1693- get_fn_init_return_vals ( expr. function . body . as_ref ( ) ) ,
1694- |this| {
1695- expr. visit_children_with_ast_path ( this, ast_path) ;
1696- } ,
1697- ) ;
1693+ let fn_value = self . enter_fn ( expr. function . span . lo . 0 , |this| {
1694+ expr. visit_children_with_ast_path ( this, ast_path) ;
1695+ } ) ;
16981696 if let Some ( ident) = & expr. ident {
16991697 self . add_value ( ident. to_id ( ) , fn_value) ;
17001698 } else {
@@ -1713,11 +1711,7 @@ impl VisitAstPath for Analyzer<'_> {
17131711 expr : & ' ast ArrowExpr ,
17141712 ast_path : & mut AstNodePath < AstParentNodeRef < ' r > > ,
17151713 ) {
1716- let init_return_values = match & * expr. body {
1717- BlockStmtOrExpr :: BlockStmt ( block) => get_fn_init_return_vals ( Some ( block) ) ,
1718- BlockStmtOrExpr :: Expr ( inner_expr) => vec ! [ self . eval_context. eval( inner_expr) ] ,
1719- } ;
1720- let fn_value = self . enter_fn ( expr. span . lo . 0 , init_return_values, |this| {
1714+ let fn_value = self . enter_fn ( expr. span . lo . 0 , |this| {
17211715 for ( index, p) in expr. params . iter ( ) . enumerate ( ) {
17221716 this. with_pat_value (
17231717 Some ( JsValue :: Argument ( this. cur_fn_ident ( ) , index) ) ,
@@ -1735,6 +1729,17 @@ impl VisitAstPath for Analyzer<'_> {
17351729 let mut ast_path =
17361730 ast_path. with_guard ( AstParentNodeRef :: ArrowExpr ( expr, ArrowExprField :: Body ) ) ;
17371731 expr. body . visit_with_ast_path ( this, & mut ast_path) ;
1732+ // If body is a single expression treat it as a Block with an return statement
1733+ if let BlockStmtOrExpr :: Expr ( inner_expr) = & * expr. body {
1734+ let implicit_return_value = self . eval_context . eval ( inner_expr) ;
1735+ this. get_mut_cur_fn_return_values ( )
1736+ . unwrap ( )
1737+ . push ( implicit_return_value) ;
1738+ this. early_return_stack . push ( EarlyReturn :: Always {
1739+ prev_effects : take ( & mut this. effects ) ,
1740+ start_ast_path : as_parent_path ( & ast_path) ,
1741+ } ) ;
1742+ }
17381743 }
17391744 } ) ;
17401745 self . add_value (
@@ -1784,99 +1789,39 @@ impl VisitAstPath for Analyzer<'_> {
17841789 expr. visit_children_with_ast_path ( self , ast_path) ;
17851790 }
17861791
1787- // N.B. ClassMethod covers both methods and getters/setters.
1788-
1789- fn visit_class_method < ' ast : ' r , ' r > (
1790- & mut self ,
1791- node : & ' ast ClassMethod ,
1792- ast_path : & mut swc_core:: ecma:: visit:: AstNodePath < ' r > ,
1793- ) {
1794- self . enter_fn (
1795- node. function . span . lo . 0 ,
1796- get_fn_init_return_vals ( node. function . body . as_ref ( ) ) ,
1797- |this| {
1798- node. visit_children_with_ast_path ( this, ast_path) ;
1799- // TODO: do we want to track the value of the class method?
1800- this. hoisted_effects . append ( & mut this. effects ) ;
1801- } ,
1802- ) ;
1803- }
1804- fn visit_method_prop < ' ast : ' r , ' r > (
1805- & mut self ,
1806- node : & ' ast MethodProp ,
1807- ast_path : & mut swc_core:: ecma:: visit:: AstNodePath < ' r > ,
1808- ) {
1809- self . enter_fn (
1810- node. function . span . lo . 0 ,
1811- get_fn_init_return_vals ( node. function . body . as_ref ( ) ) ,
1812- |this| {
1813- node. visit_children_with_ast_path ( this, ast_path) ;
1814- // TODO: do we want to track the value of the object method?
1815- } ,
1816- ) ;
1817- }
1818-
18191792 fn visit_getter_prop < ' ast : ' r , ' r > (
18201793 & mut self ,
18211794 node : & ' ast GetterProp ,
18221795 ast_path : & mut swc_core:: ecma:: visit:: AstNodePath < ' r > ,
18231796 ) {
1824- self . enter_fn (
1825- node. span . lo . 0 ,
1826- get_fn_init_return_vals ( node. body . as_ref ( ) ) ,
1827- |this| {
1828- node. visit_children_with_ast_path ( this, ast_path) ;
1829- this. hoisted_effects . append ( & mut this. effects ) ;
1830- } ,
1831- ) ;
1797+ self . enter_fn ( node. span . lo . 0 , |this| {
1798+ node. visit_children_with_ast_path ( this, ast_path) ;
1799+ this. hoisted_effects . append ( & mut this. effects ) ;
1800+ } ) ;
18321801 }
18331802
18341803 fn visit_setter_prop < ' ast : ' r , ' r > (
18351804 & mut self ,
18361805 node : & ' ast SetterProp ,
18371806 ast_path : & mut swc_core:: ecma:: visit:: AstNodePath < ' r > ,
18381807 ) {
1839- self . enter_fn (
1840- node. span . lo . 0 ,
1841- get_fn_init_return_vals ( node. body . as_ref ( ) ) ,
1842- |this| {
1843- node. visit_children_with_ast_path ( this, ast_path) ;
1844- // TODO: do we want to track the value of the object method?
1845- this. hoisted_effects . append ( & mut this. effects ) ;
1846- } ,
1847- ) ;
1848- }
1849-
1850- fn visit_private_method < ' ast : ' r , ' r > (
1851- & mut self ,
1852- node : & ' ast PrivateMethod ,
1853- ast_path : & mut swc_core:: ecma:: visit:: AstNodePath < ' r > ,
1854- ) {
1855- self . enter_fn (
1856- node. function . span . lo . 0 ,
1857- get_fn_init_return_vals ( node. function . body . as_ref ( ) ) ,
1858- |this| {
1859- node. visit_children_with_ast_path ( this, ast_path) ;
1860- // TODO: do we want to track the value of the class method?
1861- this. hoisted_effects . append ( & mut this. effects ) ;
1862- } ,
1863- ) ;
1808+ self . enter_fn ( node. span . lo . 0 , |this| {
1809+ node. visit_children_with_ast_path ( this, ast_path) ;
1810+ // TODO: do we want to track the value of the object method?
1811+ this. hoisted_effects . append ( & mut this. effects ) ;
1812+ } ) ;
18641813 }
18651814
18661815 fn visit_constructor < ' ast : ' r , ' r > (
18671816 & mut self ,
18681817 node : & ' ast Constructor ,
18691818 ast_path : & mut swc_core:: ecma:: visit:: AstNodePath < ' r > ,
18701819 ) {
1871- self . enter_fn (
1872- node. span . lo . 0 ,
1873- get_fn_init_return_vals ( node. body . as_ref ( ) ) ,
1874- |this| {
1875- node. visit_children_with_ast_path ( this, ast_path) ;
1876- // TODO: do we want to track the value of the constructor?
1877- this. hoisted_effects . append ( & mut this. effects ) ;
1878- } ,
1879- ) ;
1820+ self . enter_fn ( node. span . lo . 0 , |this| {
1821+ node. visit_children_with_ast_path ( this, ast_path) ;
1822+ // TODO: do we want to track the value of the constructor?
1823+ this. hoisted_effects . append ( & mut this. effects ) ;
1824+ } ) ;
18801825 }
18811826
18821827 fn visit_var_decl < ' ast : ' r , ' r > (
@@ -2422,10 +2367,9 @@ impl VisitAstPath for Analyzer<'_> {
24222367 n : & ' ast BlockStmt ,
24232368 ast_path : & mut swc_core:: ecma:: visit:: AstNodePath < ' r > ,
24242369 ) {
2425- let block_type = if ast_path. len ( ) < 2 {
2426- Some ( false )
2427- } else if matches ! (
2428- & ast_path[ ast_path. len( ) - 2 ..] ,
2370+ let path_suffix = & ast_path[ ast_path. len ( ) . saturating_sub ( 2 ) ..] ;
2371+ if matches ! (
2372+ path_suffix,
24292373 [
24302374 AstParentNodeRef :: IfStmt ( _, IfStmtField :: Cons ) ,
24312375 AstParentNodeRef :: Stmt ( _, StmtField :: Block )
@@ -2442,9 +2386,12 @@ impl VisitAstPath for Analyzer<'_> {
24422386 AstParentNodeRef :: Stmt ( _, StmtField :: Block )
24432387 ]
24442388 ) {
2445- None
2389+ // Just visit children, we already handled stack manipulation in the corresponding
2390+ // handlers.
2391+ n. visit_children_with_ast_path ( self , ast_path) ;
24462392 } else if matches ! (
2447- & ast_path[ ast_path. len( ) - 2 ..] ,
2393+ path_suffix,
2394+ // NOTE: class and object methods have 'functions' as children so they match here
24482395 [ _, AstParentNodeRef :: Function ( _, FunctionField :: Body ) ]
24492396 | [
24502397 AstParentNodeRef :: ArrowExpr ( _, ArrowExprField :: Body ) ,
@@ -2454,34 +2401,16 @@ impl VisitAstPath for Analyzer<'_> {
24542401 | [ _, AstParentNodeRef :: SetterProp ( _, SetterPropField :: Body ) ]
24552402 | [ _, AstParentNodeRef :: Constructor ( _, ConstructorField :: Body ) ]
24562403 ) {
2457- Some ( true )
2404+ // Just visit children, we already handled everything in `enter_fn`
2405+ n. visit_children_with_ast_path ( self , ast_path) ;
24582406 } else {
2459- Some ( false )
2460- } ;
2461- match block_type {
2462- Some ( true ) => {
2463- let early_return_stack = take ( & mut self . early_return_stack ) ;
2464- let mut effects = take ( & mut self . effects ) ;
2465- let hoisted_effects = take ( & mut self . hoisted_effects ) ;
2466- n. visit_children_with_ast_path ( self , ast_path) ;
2467- self . end_early_return_block ( ) ;
2468- self . effects . append ( & mut self . hoisted_effects ) ;
2469- effects. append ( & mut self . effects ) ;
2470- self . hoisted_effects = hoisted_effects;
2471- self . effects = effects;
2472- self . early_return_stack = early_return_stack;
2473- }
2474- Some ( false ) => {
2475- n. visit_children_with_ast_path ( self , ast_path) ;
2476- if self . end_early_return_block ( ) {
2477- self . early_return_stack . push ( EarlyReturn :: Always {
2478- prev_effects : take ( & mut self . effects ) ,
2479- start_ast_path : as_parent_path ( ast_path) ,
2480- } ) ;
2481- }
2482- }
2483- None => {
2484- n. visit_children_with_ast_path ( self , ast_path) ;
2407+ // These are anonymous blocks
2408+ n. visit_children_with_ast_path ( self , ast_path) ;
2409+ if self . end_early_return_block ( ) {
2410+ self . early_return_stack . push ( EarlyReturn :: Always {
2411+ prev_effects : take ( & mut self . effects ) ,
2412+ start_ast_path : as_parent_path ( ast_path) ,
2413+ } ) ;
24852414 }
24862415 }
24872416 }
@@ -2843,21 +2772,3 @@ fn extract_var_from_umd_factory(callee: &Expr, args: &[ExprOrSpread]) -> Option<
28432772
28442773 None
28452774}
2846-
2847- fn get_fn_init_return_vals ( fn_body_stmts : Option < & BlockStmt > ) -> Vec < JsValue > {
2848- let has_final_return_val = match fn_body_stmts {
2849- Some ( fn_body_stmts) => {
2850- matches ! (
2851- fn_body_stmts. stmts. last( ) ,
2852- Some ( Stmt :: Return ( ReturnStmt { arg: Some ( _) , .. } ) )
2853- )
2854- }
2855- None => false ,
2856- } ;
2857-
2858- if has_final_return_val {
2859- vec ! [ ]
2860- } else {
2861- vec ! [ JsValue :: Constant ( ConstantValue :: Undefined ) ]
2862- }
2863- }
0 commit comments