summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-01-16 19:38:07 +0000
committerBram Moolenaar <Bram@vim.org>2022-01-16 19:38:07 +0000
commitc665dabdf4c49a0fbf1dc566253c75c2abe2effa (patch)
tree3f55d76cf3fed62974742d4739836cc3cb554d09
parentc84287d6d8dd055bb6e30605465a23a8addb6fde (diff)
downloadvim-git-8.2.4115.tar.gz
patch 8.2.4115: cannot use a method with a complex expressionv8.2.4115
Problem: Cannot use a method with a complex expression. Solution: Evaluate the expression after "->" and use the result.
-rw-r--r--src/errors.h2
-rw-r--r--src/eval.c101
-rw-r--r--src/testdir/test_vim9_expr.vim23
-rw-r--r--src/version.c2
4 files changed, 78 insertions, 50 deletions
diff --git a/src/errors.h b/src/errors.h
index 5e9b6af5d..e576f810c 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -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
diff --git a/src/eval.c b/src/eval.c
index 935f19aa7..c8907defd 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -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;
}
diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim
index e1b48d7db..263b6d310 100644
--- a/src/testdir/test_vim9_expr.vim
+++ b/src/testdir/test_vim9_expr.vim
@@ -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()
diff --git a/src/version.c b/src/version.c
index d75555958..83b979f6c 100644
--- 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 */
/**/
+ 4115,
+/**/
4114,
/**/
4113,