0
0
mirror of https://github.com/vim/vim.git synced 2025-09-25 03:54:15 -04:00

patch 8.2.4115: cannot use a method with a complex expression

Problem:    Cannot use a method with a complex expression.
Solution:   Evaluate the expression after "->" and use the result.
This commit is contained in:
Bram Moolenaar
2022-01-16 19:38:07 +00:00
parent c84287d6d8
commit c665dabdf4
4 changed files with 79 additions and 51 deletions

View 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")); INIT(= N_("E1263: Using autoload in a script not under an autoload directory"));
EXTERN char e_autoload_import_cannot_use_absolute_or_relative_path[] EXTERN char e_autoload_import_cannot_use_absolute_or_relative_path[]
INIT(= N_("E1264: Autoload import cannot use absolute or relative path: %s")); 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 #endif

View File

@@ -3948,6 +3948,7 @@ eval_method(
char_u *name; char_u *name;
long len; long len;
char_u *alias; char_u *alias;
char_u *tofree = NULL;
typval_T base = *rettv; typval_T base = *rettv;
int ret = OK; int ret = OK;
int evaluate = evalarg != NULL int evaluate = evalarg != NULL
@@ -3968,67 +3969,68 @@ eval_method(
} }
else else
{ {
if (**arg == '.') char_u *paren;
{
int len2;
char_u *fname;
int idx;
imported_T *import = find_imported(name, len, TRUE,
evalarg == NULL ? NULL : evalarg->eval_cctx);
type_T *type;
// value->import.func() // If there is no "(" immediately following, but there is further on,
if (import != NULL) // 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)
{ {
name = NULL; typval_T ref;
++*arg;
fname = *arg; *arg = name;
len2 = get_name_len(arg, &alias, evaluate, TRUE); *paren = NUL;
if (len2 <= 0) ref.v_type = VAR_UNKNOWN;
if (eval7(arg, &ref, evalarg, FALSE) == FAIL)
{ {
if (verbose) *arg = name + len;
emsg(_(e_missing_name_after_dot));
ret = FAIL; ret = FAIL;
} }
else if (evaluate) else if (*skipwhite(*arg) != NUL)
{ {
int cc = fname[len2]; if (verbose)
ufunc_T *ufunc; semsg(_(e_trailing_characters_str), *arg);
ret = FAIL;
fname[len2] = NUL; }
idx = find_exported(import->imp_sid, fname, &ufunc, &type, else if (ref.v_type == VAR_FUNC && ref.vval.v_string != NULL)
evalarg->eval_cctx, verbose);
fname[len2] = cc;
if (idx >= 0)
{ {
scriptitem_T *si = SCRIPT_ITEM(import->imp_sid); name = ref.vval.v_string;
svar_T *sv = ref.vval.v_string = NULL;
((svar_T *)si->sn_var_vals.ga_data) + idx; tofree = name;
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); 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)
{
emsg(_(e_cannot_use_partial_here));
ret = FAIL;
}
else else
{ {
// TODO: how about a partial? name = vim_strsave(partial_name(ref.vval.v_partial));
if (verbose) tofree = name;
semsg(_(e_not_callable_type_str), fname); if (name == NULL)
ret = FAIL;
}
}
else if (ufunc != NULL)
{ {
name = ufunc->uf_name; ret = FAIL;
len = STRLEN(name); name = *arg;
} }
else else
len = STRLEN(name);
}
}
else
{
if (verbose)
semsg(_(e_not_callable_type_str), name);
ret = FAIL; ret = FAIL;
} }
} clear_tv(&ref);
*paren = '(';
} }
if (ret == OK) if (ret == OK)
@@ -4057,6 +4059,7 @@ eval_method(
// evaluating the arguments is possible (see test55). // evaluating the arguments is possible (see test55).
if (evaluate) if (evaluate)
clear_tv(&base); clear_tv(&base);
vim_free(tofree);
return ret; return ret;
} }

View File

@@ -3136,16 +3136,37 @@ def Test_expr7_method_call()
var sorted = [3, 1, 2] var sorted = [3, 1, 2]
-> sort() -> sort()
assert_equal([1, 2, 3], sorted) assert_equal([1, 2, 3], sorted)
END
CheckDefAndScriptSuccess(lines)
lines =<< trim END
vim9script
def SetNumber(n: number) def SetNumber(n: number)
g:number = n g:number = n
enddef enddef
const Setit = SetNumber const Setit = SetNumber
len('text')->Setit() len('text')->Setit()
assert_equal(4, g:number) 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 unlet g:number
END END
CheckDefAndScriptSuccess(lines) CheckScriptSuccess(lines) # TODO: CheckDefAndScriptSuccess()
lines =<< trim END lines =<< trim END
def RetVoid() def RetVoid()

View File

@@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
4115,
/**/ /**/
4114, 4114,
/**/ /**/