mirror of
https://github.com/vim/vim.git
synced 2025-07-25 10:54:51 -04:00
patch 9.1.0257: Vim9: :call may not find imported class members
Problem: Vim9: :call may not find imported class members (mityu) Solution: Set the typval of an imported lval variable correctly (Yegappan Lakshmanan) fixes: #14334 closes: #14386 Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
parent
78d742ab88
commit
f1750ca0c2
112
src/eval.c
112
src/eval.c
@ -1145,6 +1145,91 @@ get_lval_check_access(
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get lval information for a variable imported from script "imp_sid". On
|
||||||
|
* success, updates "lp" with the variable name, type, script ID and typval.
|
||||||
|
* The variable name starts at or after "p".
|
||||||
|
* If "rettv" is not NULL it points to the value to be assigned. This used to
|
||||||
|
* match the rhs and lhs types.
|
||||||
|
* Returns a pointer to the character after the variable name if the imported
|
||||||
|
* variable is valid and writable.
|
||||||
|
* Returns NULL if the variable is not exported or typval is not found or the
|
||||||
|
* rhs type doesn't match the lhs type or the variable is not writable.
|
||||||
|
*/
|
||||||
|
static char_u *
|
||||||
|
get_lval_imported(
|
||||||
|
lval_T *lp,
|
||||||
|
typval_T *rettv,
|
||||||
|
scid_T imp_sid,
|
||||||
|
char_u *p,
|
||||||
|
dictitem_T **dip,
|
||||||
|
int fne_flags,
|
||||||
|
int vim9script)
|
||||||
|
{
|
||||||
|
ufunc_T *ufunc;
|
||||||
|
type_T *type = NULL;
|
||||||
|
int cc;
|
||||||
|
int rc = FAIL;
|
||||||
|
|
||||||
|
p = skipwhite(p);
|
||||||
|
|
||||||
|
import_check_sourced_sid(&imp_sid);
|
||||||
|
lp->ll_sid = imp_sid;
|
||||||
|
lp->ll_name = p;
|
||||||
|
p = find_name_end(lp->ll_name, NULL, NULL, fne_flags);
|
||||||
|
lp->ll_name_end = p;
|
||||||
|
|
||||||
|
// check the item is exported
|
||||||
|
cc = *p;
|
||||||
|
*p = NUL;
|
||||||
|
if (find_exported(imp_sid, lp->ll_name, &ufunc, &type, NULL, NULL,
|
||||||
|
TRUE) == -1)
|
||||||
|
goto failed;
|
||||||
|
|
||||||
|
if (vim9script && type != NULL)
|
||||||
|
{
|
||||||
|
where_T where = WHERE_INIT;
|
||||||
|
|
||||||
|
// In a vim9 script, do type check and make sure the variable is
|
||||||
|
// writable.
|
||||||
|
if (check_typval_type(type, rettv, where) == FAIL)
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the typval for the exported item
|
||||||
|
hashtab_T *ht = &SCRIPT_VARS(imp_sid);
|
||||||
|
if (ht == NULL)
|
||||||
|
goto failed;
|
||||||
|
|
||||||
|
dictitem_T *di = find_var_in_ht(ht, 0, lp->ll_name, TRUE);
|
||||||
|
if (di == NULL)
|
||||||
|
// variable is not found
|
||||||
|
goto success;
|
||||||
|
|
||||||
|
*dip = di;
|
||||||
|
|
||||||
|
// Check whether the variable is writable.
|
||||||
|
svar_T *sv = find_typval_in_script(&di->di_tv, imp_sid, FALSE);
|
||||||
|
if (sv != NULL && sv->sv_const != 0)
|
||||||
|
{
|
||||||
|
semsg(_(e_cannot_change_readonly_variable_str), lp->ll_name);
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check whether variable is locked
|
||||||
|
if (value_check_lock(di->di_tv.v_lock, lp->ll_name, FALSE))
|
||||||
|
goto failed;
|
||||||
|
|
||||||
|
lp->ll_tv = &di->di_tv;
|
||||||
|
|
||||||
|
success:
|
||||||
|
rc = OK;
|
||||||
|
|
||||||
|
failed:
|
||||||
|
*p = cc;
|
||||||
|
return rc == OK ? p : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get an lval: variable, Dict item or List item that can be assigned a value
|
* Get an lval: variable, Dict item or List item that can be assigned a value
|
||||||
* to: "name", "na{me}", "name[expr]", "name[expr:expr]", "name[expr][expr]",
|
* to: "name", "na{me}", "name[expr]", "name[expr:expr]", "name[expr][expr]",
|
||||||
@ -1177,7 +1262,7 @@ get_lval(
|
|||||||
char_u *p;
|
char_u *p;
|
||||||
char_u *expr_start, *expr_end;
|
char_u *expr_start, *expr_end;
|
||||||
int cc;
|
int cc;
|
||||||
dictitem_T *v;
|
dictitem_T *v = NULL;
|
||||||
typval_T var1;
|
typval_T var1;
|
||||||
typval_T var2;
|
typval_T var2;
|
||||||
int empty1 = FALSE;
|
int empty1 = FALSE;
|
||||||
@ -1311,28 +1396,13 @@ get_lval(
|
|||||||
if (*p == '.')
|
if (*p == '.')
|
||||||
{
|
{
|
||||||
imported_T *import = find_imported(lp->ll_name, p - lp->ll_name, TRUE);
|
imported_T *import = find_imported(lp->ll_name, p - lp->ll_name, TRUE);
|
||||||
|
|
||||||
if (import != NULL)
|
if (import != NULL)
|
||||||
{
|
{
|
||||||
ufunc_T *ufunc;
|
p++; // skip '.'
|
||||||
type_T *type;
|
p = get_lval_imported(lp, rettv, import->imp_sid, p, &v,
|
||||||
|
fne_flags, vim9script);
|
||||||
import_check_sourced_sid(&import->imp_sid);
|
if (p == NULL)
|
||||||
lp->ll_sid = import->imp_sid;
|
|
||||||
lp->ll_name = skipwhite(p + 1);
|
|
||||||
p = find_name_end(lp->ll_name, NULL, NULL, fne_flags);
|
|
||||||
lp->ll_name_end = p;
|
|
||||||
|
|
||||||
// check the item is exported
|
|
||||||
cc = *p;
|
|
||||||
*p = NUL;
|
|
||||||
if (find_exported(import->imp_sid, lp->ll_name, &ufunc, &type,
|
|
||||||
NULL, NULL, TRUE) == -1)
|
|
||||||
{
|
|
||||||
*p = cc;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
*p = cc;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1352,7 +1422,7 @@ get_lval(
|
|||||||
lp->ll_tv = lval_root->lr_tv;
|
lp->ll_tv = lval_root->lr_tv;
|
||||||
v = NULL;
|
v = NULL;
|
||||||
}
|
}
|
||||||
else
|
else if (lp->ll_tv == NULL)
|
||||||
{
|
{
|
||||||
cc = *p;
|
cc = *p;
|
||||||
*p = NUL;
|
*p = NUL;
|
||||||
|
@ -3121,6 +3121,28 @@ def Test_class_import()
|
|||||||
v9.CheckScriptSuccess(lines)
|
v9.CheckScriptSuccess(lines)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
" Test for importing a class into a legacy script and calling the class method
|
||||||
|
def Test_class_method_from_legacy_script()
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
export class A
|
||||||
|
static var name: string = 'a'
|
||||||
|
static def SetName(n: string)
|
||||||
|
name = n
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
END
|
||||||
|
writefile(lines, 'Xvim9export.vim', 'D')
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
import './Xvim9export.vim' as vim9
|
||||||
|
|
||||||
|
call s:vim9.A.SetName('b')
|
||||||
|
call assert_equal('b', s:vim9.A.name)
|
||||||
|
END
|
||||||
|
v9.CheckScriptSuccess(lines)
|
||||||
|
enddef
|
||||||
|
|
||||||
" Test for implementing an imported interface
|
" Test for implementing an imported interface
|
||||||
def Test_implement_imported_interface()
|
def Test_implement_imported_interface()
|
||||||
var lines =<< trim END
|
var lines =<< trim END
|
||||||
@ -3220,6 +3242,23 @@ def Test_abstract_class()
|
|||||||
endclass
|
endclass
|
||||||
END
|
END
|
||||||
v9.CheckSourceFailure(lines, 'E1359: Cannot define a "new" method in an abstract class', 4)
|
v9.CheckSourceFailure(lines, 'E1359: Cannot define a "new" method in an abstract class', 4)
|
||||||
|
|
||||||
|
# extending an abstract class with class methods and variables
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
abstract class A
|
||||||
|
static var s: string = 'vim'
|
||||||
|
static def Fn(): list<number>
|
||||||
|
return [10]
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
class B extends A
|
||||||
|
endclass
|
||||||
|
var b = B.new()
|
||||||
|
assert_equal('vim', A.s)
|
||||||
|
assert_equal([10], A.Fn())
|
||||||
|
END
|
||||||
|
v9.CheckScriptSuccess(lines)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
def Test_closure_in_class()
|
def Test_closure_in_class()
|
||||||
|
@ -2054,6 +2054,13 @@ def Test_import_vim9_from_legacy()
|
|||||||
export def GetText(): string
|
export def GetText(): string
|
||||||
return 'text'
|
return 'text'
|
||||||
enddef
|
enddef
|
||||||
|
export var exported_nr: number = 22
|
||||||
|
def AddNum(n: number)
|
||||||
|
exported_nr += n
|
||||||
|
enddef
|
||||||
|
export var exportedDict: dict<func> = {Fn: AddNum}
|
||||||
|
export const CONST = 10
|
||||||
|
export final finalVar = 'abc'
|
||||||
END
|
END
|
||||||
writefile(vim9_lines, 'Xvim9_export.vim', 'D')
|
writefile(vim9_lines, 'Xvim9_export.vim', 'D')
|
||||||
|
|
||||||
@ -2072,6 +2079,13 @@ def Test_import_vim9_from_legacy()
|
|||||||
" imported symbol is script-local
|
" imported symbol is script-local
|
||||||
call assert_equal('exported', s:vim9.exported)
|
call assert_equal('exported', s:vim9.exported)
|
||||||
call assert_equal('text', s:vim9.GetText())
|
call assert_equal('text', s:vim9.GetText())
|
||||||
|
call s:vim9.exportedDict.Fn(5)
|
||||||
|
call assert_equal(27, s:vim9.exported_nr)
|
||||||
|
call call(s:vim9.exportedDict.Fn, [3])
|
||||||
|
call assert_equal(30, s:vim9.exported_nr)
|
||||||
|
call assert_fails('let s:vim9.CONST = 20', 'E46: Cannot change read-only variable "CONST"')
|
||||||
|
call assert_fails('let s:vim9.finalVar = ""', 'E46: Cannot change read-only variable "finalVar"')
|
||||||
|
call assert_fails('let s:vim9.non_existing_var = 20', 'E1048: Item not found in script: non_existing_var')
|
||||||
END
|
END
|
||||||
writefile(legacy_lines, 'Xlegacy_script.vim', 'D')
|
writefile(legacy_lines, 'Xlegacy_script.vim', 'D')
|
||||||
|
|
||||||
|
@ -704,6 +704,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 */
|
||||||
|
/**/
|
||||||
|
257,
|
||||||
/**/
|
/**/
|
||||||
256,
|
256,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user