Skip to content

Commit 16f2d3a

Browse files
yegappanchrisbra
authored andcommitted
patch 9.1.1146: Vim9: wrong context being used when evaluating class member
Problem: Vim9: wrong context being used when evaluating class member (lifepillar, Ernie Rael) Solution: Use the correct script context when evaluating a class member init expression(Yegappan Lakshmanan) fixes: #14011 fixes: #14402 closes: #15112 closes: #16660 Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
1 parent 5090a1f commit 16f2d3a

13 files changed

Lines changed: 197 additions & 55 deletions

src/proto/vim9compile.pro

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ int need_type(type_T *actual, type_T *expected, int number_ok, int offset, int a
1212
lvar_T *reserve_local(cctx_T *cctx, char_u *name, size_t len, int assign, type_T *type);
1313
int get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T *cctx, cstack_T *cstack);
1414
imported_T *find_imported(char_u *name, size_t len, int load);
15-
imported_T *find_imported_from_extends(cctx_T *cctx, char_u *name, size_t len, int load);
1615
char_u *may_peek_next_line(cctx_T *cctx, char_u *arg, char_u **nextp);
1716
char_u *peek_next_line_from_context(cctx_T *cctx);
1817
char_u *next_line_from_context(cctx_T *cctx, int skip_comment);

src/proto/vim9expr.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
int generate_ppconst(cctx_T *cctx, ppconst_T *ppconst);
33
void clear_ppconst(ppconst_T *ppconst);
44
int compile_member(int is_slice, int *keeping_dict, cctx_T *cctx);
5-
int compile_load_scriptvar(cctx_T *cctx, char_u *name, char_u *start, char_u **end, imported_T *import);
5+
int compile_load_scriptvar(cctx_T *cctx, char_u *name, char_u *start, char_u **end);
66
int compile_load(char_u **arg, char_u *end_arg, cctx_T *cctx, int is_expr, int error);
77
int compile_arguments(char_u **arg, cctx_T *cctx, int *argcount, ca_special_T special_fn);
88
char_u *to_name_end(char_u *arg, int use_namespace);

src/proto/vim9instr.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ int generate_undo_cmdmods(cctx_T *cctx);
8181
int generate_store_var(cctx_T *cctx, assign_dest_T dest, int opt_flags, int vimvaridx, type_T *type, char_u *name, lhs_T *lhs);
8282
int inside_loop_scope(cctx_T *cctx);
8383
int generate_store_lhs(cctx_T *cctx, lhs_T *lhs, int instr_count, int is_decl);
84+
int generate_SCRIPTCTX_SET(cctx_T *cctx, sctx_T new_sctx);
8485
void may_generate_prof_end(cctx_T *cctx, int prof_lnum);
8586
void delete_instr(isn_T *isn);
8687
void clear_instr_ga(garray_T *gap);

src/structs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,6 +1568,7 @@ typedef struct {
15681568
type_T *ocm_type;
15691569
int ocm_flags;
15701570
char_u *ocm_init; // allocated
1571+
sctx_T ocm_init_sctx; // script context of the initializer expression
15711572
} ocmember_T;
15721573

15731574
// used for the lookup table of a class member index and object method index

src/testdir/test_vim9_disassemble.vim

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3633,4 +3633,33 @@ def Test_disassemble_using_script_local_funcref()
36333633
unlet g:instr
36343634
enddef
36353635

3636+
" Disassemble the code generated for using a script local variable
3637+
" in an instance variable initialization expression
3638+
def Test_disassemble_using_script_local_var_in_obj_init()
3639+
var lines =<< trim END
3640+
vim9script
3641+
const DEFAULT = 'default-obj_key'
3642+
export class ObjKey
3643+
const unique_object_id3 = DEFAULT
3644+
endclass
3645+
END
3646+
writefile(lines, 'Xscriptlocalobjinit.vim', 'D')
3647+
lines =<< trim END
3648+
vim9script
3649+
import './Xscriptlocalobjinit.vim' as obj_key
3650+
3651+
class C1 extends obj_key.ObjKey
3652+
endclass
3653+
g:instr = execute('disassemble C1.new')
3654+
END
3655+
v9.CheckScriptSuccess(lines)
3656+
assert_match('new\_s*' ..
3657+
'0 NEW C1 size \d\+\_s*' ..
3658+
'1 SCRIPTCTX_SET .*/Xscriptlocalobjinit.vim\_s*' ..
3659+
'2 LOADSCRIPT DEFAULT-0 from .*/Xscriptlocalobjinit.vim\_s*' ..
3660+
'3 SCRIPTCTX_SET .*\_s*' ..
3661+
'4 STORE_THIS 0', g:instr)
3662+
unlet g:instr
3663+
enddef
3664+
36363665
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker

src/testdir/test_vim9_import.vim

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3595,4 +3595,70 @@ enddef
35953595
" &rtp = save_rtp
35963596
" enddef
35973597

3598+
" Test for using a non-exported constant as an instance variable initiazer in an
3599+
" imported class
3600+
def Test_import_member_initializer()
3601+
var lines =<< trim END
3602+
vim9script
3603+
const DEFAULT = 'default'
3604+
export class Foo
3605+
public var x = DEFAULT
3606+
endclass
3607+
END
3608+
writefile(lines, 'Ximportclass.vim', 'D')
3609+
3610+
# The initializer for Foo.x is evaluated in the context of Ximportclass.vim.
3611+
lines =<< trim END
3612+
vim9script
3613+
import './Ximportclass.vim' as X
3614+
class Bar extends X.Foo
3615+
endclass
3616+
var o = Bar.new()
3617+
assert_equal('default', o.x)
3618+
END
3619+
v9.CheckScriptSuccess(lines)
3620+
3621+
# Another test
3622+
lines =<< trim END
3623+
vim9script
3624+
3625+
export interface IObjKey
3626+
var unique_object_id: string
3627+
endinterface
3628+
3629+
# helper sub-class.
3630+
export class ObjKey implements IObjKey
3631+
const unique_object_id = GenerateKey()
3632+
endclass
3633+
3634+
export def GenerateKey(): string
3635+
return "SomeKey"
3636+
enddef
3637+
END
3638+
writefile(lines, 'XobjKey.vim', 'D')
3639+
3640+
lines =<< trim END
3641+
vim9script
3642+
3643+
import "./XobjKey.vim" as obj_key
3644+
3645+
const GenKey = obj_key.GenerateKey
3646+
3647+
class LocalObjKey implements obj_key.IObjKey
3648+
const unique_object_id = GenKey()
3649+
endclass
3650+
3651+
type Key1 = obj_key.ObjKey
3652+
type Key2 = LocalObjKey
3653+
3654+
class C1 extends Key1
3655+
endclass
3656+
class C2 extends Key2
3657+
endclass
3658+
assert_equal('SomeKey', C1.new().unique_object_id)
3659+
assert_equal('SomeKey', C2.new().unique_object_id)
3660+
END
3661+
v9.CheckScriptSuccess(lines)
3662+
enddef
3663+
35983664
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,8 @@ static char *(features[]) =
704704

705705
static int included_patches[] =
706706
{ /* Add new patch number below this line */
707+
/**/
708+
1146,
707709
/**/
708710
1145,
709711
/**/

src/vim9.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,8 @@ typedef enum {
219219
ISN_CEXPR_AUCMD, // first part of :cexpr isn_arg.number is cmdidx
220220
ISN_CEXPR_CORE, // second part of :cexpr, uses isn_arg.cexpr
221221

222+
ISN_SCRIPTCTX_SET, // set script context for expression evaluation
223+
222224
ISN_FINISH // end marker in list of instructions
223225
} isntype_T;
224226

@@ -570,6 +572,7 @@ struct isn_S {
570572
classmember_T classmember;
571573
storeindex_T storeindex;
572574
lockunlock_T lockunlock;
575+
sctx_T setsctx;
573576
} isn_arg;
574577
};
575578

src/vim9class.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,13 @@ add_member(
204204
m->ocm_flags |= OCMFLAG_HAS_TYPE;
205205
m->ocm_type = type;
206206
if (init_expr != NULL)
207+
{
207208
m->ocm_init = init_expr;
209+
// Save the script context, we need it when evaluating or compiling the
210+
// initializer expression.
211+
m->ocm_init_sctx = current_sctx;
212+
m->ocm_init_sctx.sc_lnum += SOURCING_LNUM;
213+
}
208214
++gap->ga_len;
209215
return OK;
210216
}
@@ -1355,7 +1361,11 @@ add_class_members(class_T *cl, exarg_T *eap, garray_T *type_list_gap)
13551361
typval_T *tv = &cl->class_members_tv[i];
13561362
if (m->ocm_init != NULL)
13571363
{
1364+
sctx_T save_current_sctx = current_sctx;
1365+
1366+
current_sctx = m->ocm_init_sctx;
13581367
typval_T *etv = eval_expr(m->ocm_init, eap);
1368+
current_sctx = save_current_sctx;
13591369
if (etv == NULL)
13601370
return FAIL;
13611371

src/vim9compile.c

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -836,30 +836,6 @@ find_imported(char_u *name, size_t len, int load)
836836
return ret;
837837
}
838838

839-
/*
840-
* Find "name" in imported items of extended base class of the class to which
841-
* the context :def function belongs.
842-
*/
843-
imported_T *
844-
find_imported_from_extends(cctx_T *cctx, char_u *name, size_t len, int load)
845-
{
846-
if (cctx == NULL || cctx->ctx_ufunc == NULL
847-
|| cctx->ctx_ufunc->uf_class == NULL)
848-
return NULL;
849-
850-
class_T *cl_extends = cctx->ctx_ufunc->uf_class->class_extends;
851-
if (cl_extends == NULL
852-
|| cl_extends->class_class_function_count_child <= 0)
853-
return NULL;
854-
855-
sctx_T current_sctx_save = current_sctx;
856-
current_sctx = cl_extends->class_class_functions[0]->uf_script_ctx;
857-
imported_T *ret = find_imported(name, len, load);
858-
current_sctx = current_sctx_save;
859-
860-
return ret;
861-
}
862-
863839
/*
864840
* Called when checking for a following operator at "arg". When the rest of
865841
* the line is empty or only a comment, peek the next line. If there is a next
@@ -1398,7 +1374,7 @@ generate_loadvar(cctx_T *cctx, lhs_T *lhs)
13981374
case dest_script:
13991375
case dest_script_v9:
14001376
res = compile_load_scriptvar(cctx,
1401-
name + (name[1] == ':' ? 2 : 0), NULL, NULL, NULL);
1377+
name + (name[1] == ':' ? 2 : 0), NULL, NULL);
14021378
break;
14031379
case dest_env:
14041380
// Include $ in the name here
@@ -3995,9 +3971,34 @@ obj_constructor_prologue(ufunc_T *ufunc, cctx_T *cctx)
39953971

39963972
if (m->ocm_init != NULL)
39973973
{
3998-
char_u *expr = m->ocm_init;
3974+
char_u *expr = m->ocm_init;
3975+
sctx_T save_current_sctx;
3976+
int change_sctx = FALSE;
3977+
3978+
// If the member variable initialization script context is
3979+
// different from the current script context, then change it.
3980+
if (current_sctx.sc_sid != m->ocm_init_sctx.sc_sid)
3981+
change_sctx = TRUE;
3982+
3983+
if (change_sctx)
3984+
{
3985+
// generate an instruction to change the script context to the
3986+
// member variable initialization script context.
3987+
save_current_sctx = current_sctx;
3988+
current_sctx = m->ocm_init_sctx;
3989+
generate_SCRIPTCTX_SET(cctx, current_sctx);
3990+
}
3991+
3992+
int r = compile_expr0(&expr, cctx);
3993+
3994+
if (change_sctx)
3995+
{
3996+
// restore the previous script context
3997+
current_sctx = save_current_sctx;
3998+
generate_SCRIPTCTX_SET(cctx, current_sctx);
3999+
}
39994000

4000-
if (compile_expr0(&expr, cctx) == FAIL)
4001+
if (r == FAIL)
40014002
return FAIL;
40024003

40034004
if (!ends_excmd2(m->ocm_init, expr))

0 commit comments

Comments
 (0)