@@ -150,6 +150,7 @@ static int
150150# endif
151151 prof_self_cmp (const void * s1 , const void * s2 );
152152#endif
153+ static void funccal_unref (funccall_T * fc , ufunc_T * fp );
153154
154155 void
155156func_init ()
@@ -257,6 +258,23 @@ get_function_args(
257258 return FAIL ;
258259}
259260
261+ /*
262+ * Register function "fp" as using "current_funccal" as its scope.
263+ */
264+ static int
265+ register_closure (ufunc_T * fp )
266+ {
267+ funccal_unref (fp -> uf_scoped , NULL );
268+ fp -> uf_scoped = current_funccal ;
269+ current_funccal -> fc_refcount ++ ;
270+ if (ga_grow (& current_funccal -> fc_funcs , 1 ) == FAIL )
271+ return FAIL ;
272+ ((ufunc_T * * )current_funccal -> fc_funcs .ga_data )
273+ [current_funccal -> fc_funcs .ga_len ++ ] = fp ;
274+ func_ref (current_funccal -> func -> uf_name );
275+ return OK ;
276+ }
277+
260278/*
261279 * Parse a lambda expression and get a Funcref from "*arg".
262280 * Return OK or FAIL. Returns NOTDONE for dict or {expr}.
@@ -318,7 +336,7 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
318336
319337 sprintf ((char * )name , "<lambda>%d" , ++ lambda_no );
320338
321- fp = (ufunc_T * )alloc ((unsigned )(sizeof (ufunc_T ) + STRLEN (name )));
339+ fp = (ufunc_T * )alloc_clear ((unsigned )(sizeof (ufunc_T ) + STRLEN (name )));
322340 if (fp == NULL )
323341 goto errret ;
324342
@@ -343,13 +361,8 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
343361 if (current_funccal != NULL && eval_lavars )
344362 {
345363 flags |= FC_CLOSURE ;
346- fp -> uf_scoped = current_funccal ;
347- current_funccal -> fc_refcount ++ ;
348- if (ga_grow (& current_funccal -> fc_funcs , 1 ) == FAIL )
364+ if (register_closure (fp ) == FAIL )
349365 goto errret ;
350- ((ufunc_T * * )current_funccal -> fc_funcs .ga_data )
351- [current_funccal -> fc_funcs .ga_len ++ ] = fp ;
352- func_ref (current_funccal -> func -> uf_name );
353366 }
354367 else
355368 fp -> uf_scoped = NULL ;
@@ -660,8 +673,15 @@ free_funccal(
660673 ufunc_T * fp = ((ufunc_T * * )(fc -> fc_funcs .ga_data ))[i ];
661674
662675 if (fp != NULL )
663- fp -> uf_scoped = NULL ;
676+ {
677+ /* Function may have been redefined and point to another
678+ * funccall_T, don't clear it then. */
679+ if (fp -> uf_scoped == fc )
680+ fp -> uf_scoped = NULL ;
681+ func_unref (fc -> func -> uf_name );
682+ }
664683 }
684+ ga_clear (& fc -> fc_funcs );
665685
666686 /* The a: variables typevals may not have been allocated, only free the
667687 * allocated variables. */
@@ -675,15 +695,6 @@ free_funccal(
675695 for (li = fc -> l_varlist .lv_first ; li != NULL ; li = li -> li_next )
676696 clear_tv (& li -> li_tv );
677697
678- for (i = 0 ; i < fc -> fc_funcs .ga_len ; ++ i )
679- {
680- ufunc_T * fp = ((ufunc_T * * )(fc -> fc_funcs .ga_data ))[i ];
681-
682- if (fp != NULL )
683- func_unref (fc -> func -> uf_name );
684- }
685- ga_clear (& fc -> fc_funcs );
686-
687698 func_unref (fc -> func -> uf_name );
688699 vim_free (fc );
689700}
@@ -1046,8 +1057,8 @@ call_user_func(
10461057 current_funccal = fc -> caller ;
10471058 -- depth ;
10481059
1049- /* If the a:000 list and the l: and a: dicts are not referenced we can
1050- * free the funccall_T and what's in it. */
1060+ /* If the a:000 list and the l: and a: dicts are not referenced and there
1061+ * is no closure using it, we can free the funccall_T and what's in it. */
10511062 if (fc -> l_varlist .lv_refcount == DO_NOT_FREE_CNT
10521063 && fc -> l_vars .dv_refcount == DO_NOT_FREE_CNT
10531064 && fc -> l_avars .dv_refcount == DO_NOT_FREE_CNT
@@ -1061,8 +1072,8 @@ call_user_func(
10611072 listitem_T * li ;
10621073 int todo ;
10631074
1064- /* "fc" is still in use. This can happen when returning "a:000" or
1065- * assigning "l:" to a global variable.
1075+ /* "fc" is still in use. This can happen when returning "a:000",
1076+ * assigning "l:" to a global variable or defining a closure .
10661077 * Link "fc" in the list for garbage collection later. */
10671078 fc -> caller = previous_funccal ;
10681079 previous_funccal = fc ;
@@ -1121,13 +1132,11 @@ funccal_unref(funccall_T *fc, ufunc_T *fp)
11211132 func_unref (fc -> func -> uf_name );
11221133
11231134 if (fp != NULL )
1124- {
11251135 for (i = 0 ; i < fc -> fc_funcs .ga_len ; ++ i )
11261136 {
11271137 if (((ufunc_T * * )(fc -> fc_funcs .ga_data ))[i ] == fp )
11281138 ((ufunc_T * * )(fc -> fc_funcs .ga_data ))[i ] = NULL ;
11291139 }
1130- }
11311140 }
11321141}
11331142
@@ -1976,6 +1985,12 @@ ex_function(exarg_T *eap)
19761985 {
19771986 flags |= FC_CLOSURE ;
19781987 p += 7 ;
1988+ if (current_funccal == NULL )
1989+ {
1990+ emsg_funcname (N_ ("E932 Closure function should not be at top level: %s" ),
1991+ name == NULL ? (char_u * )"" : name );
1992+ goto erret ;
1993+ }
19791994 }
19801995 else
19811996 break ;
@@ -2265,7 +2280,7 @@ ex_function(exarg_T *eap)
22652280 }
22662281 }
22672282
2268- fp = (ufunc_T * )alloc ((unsigned )(sizeof (ufunc_T ) + STRLEN (name )));
2283+ fp = (ufunc_T * )alloc_clear ((unsigned )(sizeof (ufunc_T ) + STRLEN (name )));
22692284 if (fp == NULL )
22702285 goto erret ;
22712286
@@ -2311,19 +2326,9 @@ ex_function(exarg_T *eap)
23112326 fp -> uf_lines = newlines ;
23122327 if ((flags & FC_CLOSURE ) != 0 )
23132328 {
2314- if (current_funccal == NULL )
2315- {
2316- emsg_funcname (N_ ("E932 Closure function should not be at top level: %s" ),
2317- name );
2329+ ++ fp -> uf_refcount ;
2330+ if (register_closure (fp ) == FAIL )
23182331 goto erret ;
2319- }
2320- fp -> uf_scoped = current_funccal ;
2321- current_funccal -> fc_refcount ++ ;
2322- if (ga_grow (& current_funccal -> fc_funcs , 1 ) == FAIL )
2323- goto erret ;
2324- ((ufunc_T * * )current_funccal -> fc_funcs .ga_data )
2325- [current_funccal -> fc_funcs .ga_len ++ ] = fp ;
2326- func_ref (current_funccal -> func -> uf_name );
23272332 }
23282333 else
23292334 fp -> uf_scoped = NULL ;
@@ -3582,21 +3587,21 @@ find_hi_in_scoped_ht(char_u *name, char_u **varname, hashtab_T **pht)
35823587
35833588 /* Search in parent scope which is possible to reference from lambda */
35843589 current_funccal = current_funccal -> func -> uf_scoped ;
3585- while (current_funccal )
3590+ while (current_funccal != NULL )
35863591 {
3587- ht = find_var_ht (name , varname );
3588- if (ht != NULL && * * varname != NUL )
3589- {
3590- hi = hash_find (ht , * varname );
3591- if (!HASHITEM_EMPTY (hi ))
3592- {
3593- * pht = ht ;
3594- break ;
3595- }
3596- }
3597- if (current_funccal == current_funccal -> func -> uf_scoped )
3598- break ;
3599- current_funccal = current_funccal -> func -> uf_scoped ;
3592+ ht = find_var_ht (name , varname );
3593+ if (ht != NULL && * * varname != NUL )
3594+ {
3595+ hi = hash_find (ht , * varname );
3596+ if (!HASHITEM_EMPTY (hi ))
3597+ {
3598+ * pht = ht ;
3599+ break ;
3600+ }
3601+ }
3602+ if (current_funccal == current_funccal -> func -> uf_scoped )
3603+ break ;
3604+ current_funccal = current_funccal -> func -> uf_scoped ;
36003605 }
36013606 current_funccal = old_current_funccal ;
36023607
0 commit comments