diff src/userfunc.c @ 20528:489cb75c76b6 v8.2.0818

patch 8.2.0818: Vim9: using a discovery phase doesn't work well Commit: https://github.com/vim/vim/commit/822ba24743af9ee1b5e7f656a7a61a38f3638bca Author: Bram Moolenaar <Bram@vim.org> Date: Sun May 24 23:00:18 2020 +0200 patch 8.2.0818: Vim9: using a discovery phase doesn't work well Problem: Vim9: using a discovery phase doesn't work well. Solution: Remove the discovery phase, instead compile a function only when it is used. Add :defcompile to compile def functions earlier.
author Bram Moolenaar <Bram@vim.org>
date Sun, 24 May 2020 23:15:04 +0200
parents 5950284a517f
children cb4831fa7e25
line wrap: on
line diff
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -409,7 +409,7 @@ get_lambda_tv(char_u **arg, typval_T *re
 	fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
 	if (fp == NULL)
 	    goto errret;
-	fp->uf_dfunc_idx = -1;
+	fp->uf_dfunc_idx = UF_NOT_COMPILED;
 	pt = ALLOC_CLEAR_ONE(partial_T);
 	if (pt == NULL)
 	    goto errret;
@@ -1112,7 +1112,7 @@ call_user_func(
     ga_init2(&fc->fc_funcs, sizeof(ufunc_T *), 1);
     func_ptr_ref(fp);
 
-    if (fp->uf_dfunc_idx >= 0)
+    if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
     {
 	estack_push_ufunc(ETYPE_UFUNC, fp, 1);
 	save_current_sctx = current_sctx;
@@ -1637,7 +1637,7 @@ free_all_functions(void)
 		// clear the def function index now
 		fp = HI2UF(hi);
 		fp->uf_flags &= ~FC_DEAD;
-		fp->uf_dfunc_idx = -1;
+		fp->uf_dfunc_idx = UF_NOT_COMPILED;
 
 		// Only free functions that are not refcounted, those are
 		// supposed to be freed when no longer referenced.
@@ -2033,7 +2033,7 @@ list_func_head(ufunc_T *fp, int indent)
     msg_start();
     if (indent)
 	msg_puts("   ");
-    if (fp->uf_dfunc_idx >= 0)
+    if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
 	msg_puts("def ");
     else
 	msg_puts("function ");
@@ -2082,7 +2082,7 @@ list_func_head(ufunc_T *fp, int indent)
     }
     msg_putchar(')');
 
-    if (fp->uf_dfunc_idx >= 0)
+    if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
     {
 	if (fp->uf_ret_type != &t_void)
 	{
@@ -2377,7 +2377,7 @@ untrans_function_name(char_u *name)
  * Returns a pointer to the function or NULL if no function defined.
  */
     ufunc_T *
-def_function(exarg_T *eap, char_u *name_arg, void *context, int compile)
+def_function(exarg_T *eap, char_u *name_arg)
 {
     char_u	*theline;
     char_u	*line_to_free = NULL;
@@ -2416,6 +2416,12 @@ def_function(exarg_T *eap, char_u *name_
     char_u	*skip_until = NULL;
     char_u	*heredoc_trimmed = NULL;
 
+    if (in_vim9script() && eap->forceit)
+    {
+	emsg(_(e_nobang));
+	return NULL;
+    }
+
     /*
      * ":function" without argument: list functions.
      */
@@ -2584,7 +2590,7 @@ def_function(exarg_T *eap, char_u *name_
 		if (!got_int)
 		{
 		    msg_putchar('\n');
-		    if (fp->uf_dfunc_idx >= 0)
+		    if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
 			msg_puts("   enddef");
 		    else
 			msg_puts("   endfunction");
@@ -3122,7 +3128,8 @@ def_function(exarg_T *eap, char_u *name_
 	fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
 	if (fp == NULL)
 	    goto erret;
-	fp->uf_dfunc_idx = -1;
+	fp->uf_dfunc_idx = eap->cmdidx == CMD_def ? UF_TO_BE_COMPILED
+							     : UF_NOT_COMPILED;
 
 	if (fudi.fd_dict != NULL)
 	{
@@ -3175,6 +3182,8 @@ def_function(exarg_T *eap, char_u *name_
     {
 	int	lnum_save = SOURCING_LNUM;
 
+	fp->uf_dfunc_idx = UF_TO_BE_COMPILED;
+
 	// error messages are for the first function line
 	SOURCING_LNUM = sourcing_lnum_top;
 
@@ -3242,6 +3251,8 @@ def_function(exarg_T *eap, char_u *name_
 	}
 	SOURCING_LNUM = lnum_save;
     }
+    else
+	fp->uf_dfunc_idx = UF_NOT_COMPILED;
 
     fp->uf_lines = newlines;
     if ((flags & FC_CLOSURE) != 0)
@@ -3273,10 +3284,6 @@ def_function(exarg_T *eap, char_u *name_
 	is_export = FALSE;
     }
 
-    // ":def Func()" may need to be compiled
-    if (eap->cmdidx == CMD_def && compile)
-	compile_def_function(fp, FALSE, context);
-
     goto ret_free;
 
 erret:
@@ -3304,7 +3311,30 @@ ret_free:
     void
 ex_function(exarg_T *eap)
 {
-    (void)def_function(eap, NULL, NULL, TRUE);
+    (void)def_function(eap, NULL);
+}
+
+/*
+ * :defcompile - compile all :def functions in the current script.
+ */
+    void
+ex_defcompile(exarg_T *eap UNUSED)
+{
+    int		todo = (int)func_hashtab.ht_used;
+    hashitem_T	*hi;
+    ufunc_T	*ufunc;
+
+    for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi)
+    {
+	if (!HASHITEM_EMPTY(hi))
+	{
+	    --todo;
+	    ufunc = HI2UF(hi);
+	    if (ufunc->uf_script_ctx.sc_sid == current_sctx.sc_sid
+		    && ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED)
+		compile_def_function(ufunc, FALSE, NULL);
+	}
+    }
 }
 
 /*