changeset 27146:648a5f658990 v8.2.4102

patch 8.2.4102: Vim9: import cannot be used after method Commit: https://github.com/vim/vim/commit/857c8bb1bbe754cf2c5b709703d2eb848c800285 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Jan 15 21:08:19 2022 +0000 patch 8.2.4102: Vim9: import cannot be used after method Problem: Vim9: import cannot be used after method. Solution: Recognize an imported function name. (closes https://github.com/vim/vim/issues/9496)
author Bram Moolenaar <Bram@vim.org>
date Sat, 15 Jan 2022 22:15:03 +0100
parents 77a4efb391c0
children bcaefb769725
files src/eval.c src/testdir/test_vim9_import.vim src/version.c
diffstat 3 files changed, 87 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/src/eval.c
+++ b/src/eval.c
@@ -3949,7 +3949,7 @@ eval_method(
     long	len;
     char_u	*alias;
     typval_T	base = *rettv;
-    int		ret;
+    int		ret = OK;
     int		evaluate = evalarg != NULL
 				      && (evalarg->eval_flags & EVAL_EVALUATE);
 
@@ -3968,22 +3968,87 @@ eval_method(
     }
     else
     {
-	*arg = skipwhite(*arg);
-	if (**arg != '(')
+	if (**arg == '.')
 	{
-	    if (verbose)
-		semsg(_(e_missing_parenthesis_str), name);
-	    ret = FAIL;
+	    int		len2;
+	    char_u	*fname;
+	    int		idx;
+	    imported_T	*import = find_imported(name, len,
+						     TRUE, evalarg->eval_cctx);
+	    type_T	*type;
+
+	    // value->import.func()
+	    if (import != NULL)
+	    {
+		name = NULL;
+		++*arg;
+		fname = *arg;
+		len2 = get_name_len(arg, &alias, evaluate, TRUE);
+		if (len2 <= 0)
+		{
+		    emsg(_(e_missing_name_after_dot));
+		    ret = FAIL;
+		}
+		else
+		{
+		    int	    cc = fname[len2];
+		    ufunc_T *ufunc;
+
+		    fname[len2] = NUL;
+		    idx = find_exported(import->imp_sid, fname, &ufunc, &type,
+						  evalarg->eval_cctx, verbose);
+		    fname[len2] = cc;
+
+		    if (idx >= 0)
+		    {
+			scriptitem_T    *si = SCRIPT_ITEM(import->imp_sid);
+			svar_T		*sv =
+				     ((svar_T *)si->sn_var_vals.ga_data) + idx;
+
+			if (sv->sv_tv->v_type == VAR_FUNC
+					   && sv->sv_tv->vval.v_string != NULL)
+			{
+			    name = sv->sv_tv->vval.v_string;
+			    len = STRLEN(name);
+			}
+			else
+			{
+			    // TODO: how about a partial?
+			    semsg(_(e_not_callable_type_str), fname);
+			    ret = FAIL;
+			}
+		    }
+		    else if (ufunc != NULL)
+		    {
+			name = ufunc->uf_name;
+			len = STRLEN(name);
+		    }
+		    else
+			ret = FAIL;
+		}
+	    }
 	}
-	else if (VIM_ISWHITE((*arg)[-1]))
+
+	if (ret == OK)
 	{
-	    if (verbose)
-		emsg(_(e_no_white_space_allowed_before_parenthesis));
-	    ret = FAIL;
+	    *arg = skipwhite(*arg);
+
+	    if (**arg != '(')
+	    {
+		if (verbose)
+		    semsg(_(e_missing_parenthesis_str), name);
+		ret = FAIL;
+	    }
+	    else if (VIM_ISWHITE((*arg)[-1]))
+	    {
+		if (verbose)
+		    emsg(_(e_no_white_space_allowed_before_parenthesis));
+		ret = FAIL;
+	    }
+	    else
+		ret = eval_func(arg, evalarg, name, len, rettv,
+					  evaluate ? EVAL_EVALUATE : 0, &base);
 	}
-	else
-	    ret = eval_func(arg, evalarg, name, len, rettv,
-					  evaluate ? EVAL_EVALUATE : 0, &base);
     }
 
     // Clear the funcref afterwards, so that deleting it while
--- a/src/testdir/test_vim9_import.vim
+++ b/src/testdir/test_vim9_import.vim
@@ -27,6 +27,10 @@ let s:export_script_lines =<< trim END
     exported += 5
   enddef
   export final theList = [1]
+  export def AddSome(s: string): string
+    return s .. 'some'
+  enddef
+  export var AddRef = AddSome
 END
 
 def Undo_export_script_lines()
@@ -70,6 +74,9 @@ def Test_vim9_import_export()
 
     expo.theList->add(2)
     assert_equal([1, 2], expo.theList)
+
+    assert_equal('andthensome', 'andthen'->expo.AddSome())
+    assert_equal('awesome', 'awe'->expo.AddRef())
   END
   writefile(import_script_lines, 'Ximport.vim')
   source Ximport.vim
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    4102,
+/**/
     4101,
 /**/
     4100,