mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	vim-patch:7.4.2136
Problem:    Closure function fails.
Solution:   Don't reset uf_scoped when it points to another funccal.
5801644819
			
			
This commit is contained in:
		| @@ -7018,6 +7018,18 @@ err_ret: | |||||||
|   return FAIL; |   return FAIL; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Register function "fp" as using "current_funccal" as its scope. | ||||||
|  | static int register_closure(ufunc_T *fp) { | ||||||
|  |   funccal_unref(fp->uf_scoped, NULL); | ||||||
|  |   fp->uf_scoped = current_funccal; | ||||||
|  |   current_funccal->fc_refcount++; | ||||||
|  |   ga_grow(¤t_funccal->fc_funcs, 1); | ||||||
|  |   ((ufunc_T **)current_funccal->fc_funcs.ga_data) | ||||||
|  |     [current_funccal->fc_funcs.ga_len++] = fp; | ||||||
|  |   func_ref(current_funccal->func->uf_name); | ||||||
|  |   return OK; | ||||||
|  | } | ||||||
|  |  | ||||||
| /// Parse a lambda expression and get a Funcref from "*arg". | /// Parse a lambda expression and get a Funcref from "*arg". | ||||||
| /// | /// | ||||||
| /// @return OK or FAIL.  Returns NOTDONE for dict or {expr}. | /// @return OK or FAIL.  Returns NOTDONE for dict or {expr}. | ||||||
| @@ -7083,7 +7095,7 @@ static int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate) | |||||||
|  |  | ||||||
|     snprintf((char *)name, sizeof(name), "<lambda>%d", lambda_no++); |     snprintf((char *)name, sizeof(name), "<lambda>%d", lambda_no++); | ||||||
|  |  | ||||||
|     fp = (ufunc_T *)xmalloc((unsigned)(sizeof(ufunc_T) + STRLEN(name))); |     fp = (ufunc_T *)xcalloc(1, (unsigned)(sizeof(ufunc_T) + STRLEN(name))); | ||||||
|     if (fp == NULL) { |     if (fp == NULL) { | ||||||
|       goto errret; |       goto errret; | ||||||
|     } |     } | ||||||
| @@ -7109,12 +7121,7 @@ static int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate) | |||||||
|     fp->uf_lines = newlines; |     fp->uf_lines = newlines; | ||||||
|     if (current_funccal != NULL && eval_lavars) { |     if (current_funccal != NULL && eval_lavars) { | ||||||
|       flags |= FC_CLOSURE; |       flags |= FC_CLOSURE; | ||||||
|       fp->uf_scoped = current_funccal; |       register_closure(fp); | ||||||
|       current_funccal->fc_refcount++; |  | ||||||
|       ga_grow(¤t_funccal->fc_funcs, 1); |  | ||||||
|       ((ufunc_T **)current_funccal->fc_funcs.ga_data) |  | ||||||
|        [current_funccal->fc_funcs.ga_len++] = fp; |  | ||||||
|       func_ref(current_funccal->func->uf_name); |  | ||||||
|     } else { |     } else { | ||||||
|       fp->uf_scoped = NULL; |       fp->uf_scoped = NULL; | ||||||
|     } |     } | ||||||
| @@ -21076,6 +21083,12 @@ void ex_function(exarg_T *eap) | |||||||
|     } else if (STRNCMP(p, "closure", 7) == 0) { |     } else if (STRNCMP(p, "closure", 7) == 0) { | ||||||
|       flags |= FC_CLOSURE; |       flags |= FC_CLOSURE; | ||||||
|       p += 7; |       p += 7; | ||||||
|  |       if (current_funccal == NULL) { | ||||||
|  |         emsg_funcname(N_ | ||||||
|  |                       ("E932 Closure function should not be at top level: %s"), | ||||||
|  |                       name == NULL ? (char_u *)"" : name); | ||||||
|  |         goto erret; | ||||||
|  |       } | ||||||
|     } else { |     } else { | ||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
| @@ -21329,7 +21342,7 @@ void ex_function(exarg_T *eap) | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fp = xmalloc(sizeof(ufunc_T) + STRLEN(name)); |     fp = xcalloc(1, sizeof(ufunc_T) + STRLEN(name)); | ||||||
|  |  | ||||||
|     if (fudi.fd_dict != NULL) { |     if (fudi.fd_dict != NULL) { | ||||||
|       if (fudi.fd_di == NULL) { |       if (fudi.fd_di == NULL) { | ||||||
| @@ -21362,17 +21375,7 @@ void ex_function(exarg_T *eap) | |||||||
|   fp->uf_args = newargs; |   fp->uf_args = newargs; | ||||||
|   fp->uf_lines = newlines; |   fp->uf_lines = newlines; | ||||||
|   if ((flags & FC_CLOSURE) != 0) { |   if ((flags & FC_CLOSURE) != 0) { | ||||||
|     if (current_funccal == NULL) { |     register_closure(fp); | ||||||
|       emsg_funcname(N_("E932 Closure function should not be at top level: %s"), |  | ||||||
|                     name); |  | ||||||
|       goto erret; |  | ||||||
|     } |  | ||||||
|     fp->uf_scoped = current_funccal; |  | ||||||
|     current_funccal->fc_refcount++; |  | ||||||
|     ga_grow(¤t_funccal->fc_funcs, 1); |  | ||||||
|     ((ufunc_T **)current_funccal->fc_funcs.ga_data) |  | ||||||
|       [current_funccal->fc_funcs.ga_len++] = fp; |  | ||||||
|     func_ref(current_funccal->func->uf_name); |  | ||||||
|   } else { |   } else { | ||||||
|     fp->uf_scoped = NULL; |     fp->uf_scoped = NULL; | ||||||
|   } |   } | ||||||
| @@ -22543,8 +22546,8 @@ call_user_func ( | |||||||
|   current_funccal = fc->caller; |   current_funccal = fc->caller; | ||||||
|   --depth; |   --depth; | ||||||
|  |  | ||||||
|   /* If the a:000 list and the l: and a: dicts are not referenced we can |   // If the a:000 list and the l: and a: dicts are not referenced and there | ||||||
|    * free the funccall_T and what's in it. */ |   // is no closure using it, we can free the funccall_T and what's in it. | ||||||
|   if (fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT |   if (fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT | ||||||
|       && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT |       && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT | ||||||
|       && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT |       && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT | ||||||
| @@ -22555,9 +22558,9 @@ call_user_func ( | |||||||
|     listitem_T      *li; |     listitem_T      *li; | ||||||
|     int todo; |     int todo; | ||||||
|  |  | ||||||
|     /* "fc" is still in use.  This can happen when returning "a:000" or |     // "fc" is still in use.  This can happen when returning "a:000", | ||||||
|      * assigning "l:" to a global variable. |     // assigning "l:" to a global variable or defining a closure. | ||||||
|      * Link "fc" in the list for garbage collection later. */ |     // Link "fc" in the list for garbage collection later. | ||||||
|     fc->caller = previous_funccal; |     fc->caller = previous_funccal; | ||||||
|     previous_funccal = fc; |     previous_funccal = fc; | ||||||
|  |  | ||||||
| @@ -22653,9 +22656,15 @@ free_funccal ( | |||||||
|     ufunc_T *fp = ((ufunc_T **)(fc->fc_funcs.ga_data))[i]; |     ufunc_T *fp = ((ufunc_T **)(fc->fc_funcs.ga_data))[i]; | ||||||
|  |  | ||||||
|     if (fp != NULL) { |     if (fp != NULL) { | ||||||
|       fp->uf_scoped = NULL; |       // Function may have been redefined and point to another | ||||||
|  |       // funccall_T, don't clear it then. | ||||||
|  |       if (fp->uf_scoped == fc) { | ||||||
|  |         fp->uf_scoped = NULL; | ||||||
|  |       } | ||||||
|  |       func_unref(fc->func->uf_name); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |   ga_clear(&fc->fc_funcs): | ||||||
|  |  | ||||||
|   // The a: variables typevals may not have been allocated, only free the |   // The a: variables typevals may not have been allocated, only free the | ||||||
|   // allocated variables. |   // allocated variables. | ||||||
| @@ -22671,15 +22680,6 @@ free_funccal ( | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   for (int i = 0; i < fc->fc_funcs.ga_len; i++) { |  | ||||||
|     ufunc_T *fp = ((ufunc_T **)(fc->fc_funcs.ga_data))[i]; |  | ||||||
|  |  | ||||||
|     if (fp != NULL) { |  | ||||||
|       func_unref(fc->func->uf_name); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   ga_clear(&fc->fc_funcs); |  | ||||||
|  |  | ||||||
|   func_unref(fc->func->uf_name); |   func_unref(fc->func->uf_name); | ||||||
|   xfree(fc); |   xfree(fc); | ||||||
| } | } | ||||||
| @@ -23013,7 +23013,7 @@ hashitem_T *find_hi_in_scoped_ht(char_u *name, char_u **varname, | |||||||
|  |  | ||||||
|   // Search in parent scope which is possible to reference from lambda |   // Search in parent scope which is possible to reference from lambda | ||||||
|   current_funccal = current_funccal->func->uf_scoped; |   current_funccal = current_funccal->func->uf_scoped; | ||||||
|   while (current_funccal) { |   while (current_funccal != NULL) { | ||||||
|     ht = find_var_ht(name, varname); |     ht = find_var_ht(name, varname); | ||||||
|     if (ht != NULL && **varname != NUL) { |     if (ht != NULL && **varname != NUL) { | ||||||
|       hi = hash_find(ht, *varname); |       hi = hash_find(ht, *varname); | ||||||
|   | |||||||
| @@ -284,7 +284,3 @@ func Test_named_function_closure() | |||||||
|   call garbagecollect() |   call garbagecollect() | ||||||
|   call assert_equal(14, s:Abar()) |   call assert_equal(14, s:Abar()) | ||||||
| endfunc | endfunc | ||||||
| ======= |  | ||||||
| >>>>>>> 42b34811... vim-patch:7.4.2119 |  | ||||||
| ======= |  | ||||||
| >>>>>>> 789a3319... vim-patch:7.4.2120 |  | ||||||
|   | |||||||
| @@ -304,7 +304,7 @@ static int included_patches[] = { | |||||||
|   // 2139, |   // 2139, | ||||||
|   // 2138 NA |   // 2138 NA | ||||||
|   // 2137, |   // 2137, | ||||||
|   // 2136, |   2136, | ||||||
|   // 2135, |   // 2135, | ||||||
|   2134, |   2134, | ||||||
|   // 2133 NA |   // 2133 NA | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Michael Ennen
					Michael Ennen