]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.4115: cannot use a method with a complex expression v8.2.4115
authorBram Moolenaar <Bram@vim.org>
Sun, 16 Jan 2022 19:38:07 +0000 (19:38 +0000)
committerBram Moolenaar <Bram@vim.org>
Sun, 16 Jan 2022 19:38:07 +0000 (19:38 +0000)
Problem:    Cannot use a method with a complex expression.
Solution:   Evaluate the expression after "->" and use the result.

src/errors.h
src/eval.c
src/testdir/test_vim9_expr.vim
src/version.c

index 5e9b6af5d37d7a13f1ffbc85a4a8150a09cb7ffb..e576f810c631eaa014afc14033370ad7e382c233 100644 (file)
@@ -3212,4 +3212,6 @@ EXTERN char e_using_autoload_in_script_not_under_autoload_directory[]
        INIT(= N_("E1263: Using autoload in a script not under an autoload directory"));
 EXTERN char e_autoload_import_cannot_use_absolute_or_relative_path[]
        INIT(= N_("E1264: Autoload import cannot use absolute or relative path: %s"));
+EXTERN char e_cannot_use_partial_here[]
+       INIT(= N_("E1265: Cannot use a partial here"));
 #endif
index 935f19aa761c7572d990ce96b07421fa990b0445..c8907defd0b0f6a6eca836e8cf3e3796e3925bb1 100644 (file)
@@ -3948,6 +3948,7 @@ eval_method(
     char_u     *name;
     long       len;
     char_u     *alias;
+    char_u     *tofree = NULL;
     typval_T   base = *rettv;
     int                ret = OK;
     int                evaluate = evalarg != NULL
@@ -3968,67 +3969,68 @@ eval_method(
     }
     else
     {
-       if (**arg == '.')
+       char_u *paren;
+
+       // If there is no "(" immediately following, but there is further on,
+       // it can be "import.Func()", "dict.Func()", "list[nr]", etc.
+       // Does not handle anything where "(" is part of the expression.
+       *arg = skipwhite(*arg);
+
+       if (**arg != '(' && alias == NULL
+                                   && (paren = vim_strchr(*arg, '(')) != NULL)
        {
-           int         len2;
-           char_u      *fname;
-           int         idx;
-           imported_T  *import = find_imported(name, len, TRUE,
-                                 evalarg == NULL ? NULL : evalarg->eval_cctx);
-           type_T      *type;
+           typval_T ref;
 
-           // value->import.func()
-           if (import != NULL)
+           *arg = name;
+           *paren = NUL;
+           ref.v_type = VAR_UNKNOWN;
+           if (eval7(arg, &ref, evalarg, FALSE) == FAIL)
            {
-               name = NULL;
-               ++*arg;
-               fname = *arg;
-               len2 = get_name_len(arg, &alias, evaluate, TRUE);
-               if (len2 <= 0)
+               *arg = name + len;
+               ret = FAIL;
+           }
+           else if (*skipwhite(*arg) != NUL)
+           {
+               if (verbose)
+                   semsg(_(e_trailing_characters_str), *arg);
+               ret = FAIL;
+           }
+           else if (ref.v_type == VAR_FUNC && ref.vval.v_string != NULL)
+           {
+               name = ref.vval.v_string;
+               ref.vval.v_string = NULL;
+               tofree = name;
+               len = STRLEN(name);
+           }
+           else if (ref.v_type == VAR_PARTIAL && ref.vval.v_partial != NULL)
+           {
+               if (ref.vval.v_partial->pt_argc > 0
+                                       || ref.vval.v_partial->pt_dict != NULL)
                {
-                   if (verbose)
-                       emsg(_(e_missing_name_after_dot));
+                   emsg(_(e_cannot_use_partial_here));
                    ret = FAIL;
                }
-               else if (evaluate)
+               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)
+                   name = vim_strsave(partial_name(ref.vval.v_partial));
+                   tofree = name;
+                   if (name == NULL)
                    {
-                       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?
-                           if (verbose)
-                               semsg(_(e_not_callable_type_str), fname);
-                           ret = FAIL;
-                       }
-                   }
-                   else if (ufunc != NULL)
-                   {
-                       name = ufunc->uf_name;
-                       len = STRLEN(name);
+                       ret = FAIL;
+                       name = *arg;
                    }
                    else
-                       ret = FAIL;
+                       len = STRLEN(name);
                }
            }
+           else
+           {
+               if (verbose)
+                   semsg(_(e_not_callable_type_str), name);
+               ret = FAIL;
+           }
+               clear_tv(&ref);
+           *paren = '(';
        }
 
        if (ret == OK)
@@ -4057,6 +4059,7 @@ eval_method(
     // evaluating the arguments is possible (see test55).
     if (evaluate)
        clear_tv(&base);
+    vim_free(tofree);
 
     return ret;
 }
index e1b48d7db1825adb358e777d24774e7c30349e06..263b6d31052a26effcd608ba9394ad25b0e62a45 100644 (file)
@@ -3136,16 +3136,37 @@ def Test_expr7_method_call()
       var sorted = [3, 1, 2]
                     -> sort()
       assert_equal([1, 2, 3], sorted)
+  END
+  CheckDefAndScriptSuccess(lines)
 
+  lines =<< trim END
+      vim9script
       def SetNumber(n: number)
         g:number = n
       enddef
       const Setit = SetNumber
       len('text')->Setit()
       assert_equal(4, g:number)
+
+      const SetFuncref = funcref(SetNumber)
+      len('longer')->SetFuncref()
+      assert_equal(6, g:number)
+
+      const SetList = [SetNumber, SetFuncref]
+      len('xx')->SetList[0]()
+      assert_equal(2, g:number)
+      len('xxx')->SetList[1]()
+      assert_equal(3, g:number)
+
+      const SetDict = {key: SetNumber}
+      len('xxxx')->SetDict['key']()
+      assert_equal(4, g:number)
+      len('xxxxx')->SetDict.key()
+      assert_equal(5, g:number)
+
       unlet g:number
   END
-  CheckDefAndScriptSuccess(lines)
+  CheckScriptSuccess(lines)  # TODO: CheckDefAndScriptSuccess()
 
   lines =<< trim END
     def RetVoid()
index d7555595806e22e05817f3633ababd53caa5553e..83b979f6cd0f2f8217e06eedfa3a89f02bdccfd2 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4115,
 /**/
     4114,
 /**/