Skip to content

Commit b1b6f4d

Browse files
committed
patch 8.2.3435: Vim9: dict is not passed to dict function
Problem: Vim9: dict is not passed to dict function. Solution: Keep the dict used until a function call.
1 parent 28e591d commit b1b6f4d

File tree

6 files changed

+226
-26
lines changed

6 files changed

+226
-26
lines changed

src/testdir/test_vim9_disassemble.vim

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,8 @@ def Test_disassemble_store_index()
412412
'\d PUSHNR 0\_s*' ..
413413
'\d LOAD $0\_s*' ..
414414
'\d MEMBER dd\_s*' ..
415-
'\d STOREINDEX any\_s*' ..
415+
'\d\+ USEDICT\_s*' ..
416+
'\d\+ STOREINDEX any\_s*' ..
416417
'\d\+ RETURN void',
417418
res)
418419
enddef
@@ -1625,11 +1626,13 @@ def Test_disassemble_dict_member()
16251626
'var res = d.item\_s*' ..
16261627
'\d\+ LOAD $0\_s*' ..
16271628
'\d\+ MEMBER item\_s*' ..
1629+
'\d\+ USEDICT\_s*' ..
16281630
'\d\+ STORE $1\_s*' ..
16291631
'res = d\["item"\]\_s*' ..
16301632
'\d\+ LOAD $0\_s*' ..
16311633
'\d\+ PUSHS "item"\_s*' ..
16321634
'\d\+ MEMBER\_s*' ..
1635+
'\d\+ USEDICT\_s*' ..
16331636
'\d\+ STORE $1\_s*',
16341637
instr)
16351638
assert_equal(1, DictMember())
@@ -2302,6 +2305,35 @@ def Test_debug_elseif()
23022305
res)
23032306
enddef
23042307

2308+
func Legacy() dict
2309+
echo 'legacy'
2310+
endfunc
2311+
2312+
def s:UseMember()
2313+
var d = {func: Legacy}
2314+
var v = d.func()
2315+
enddef
2316+
2317+
def Test_disassemble_dict_stack()
2318+
var res = execute('disass s:UseMember')
2319+
assert_match('<SNR>\d*_UseMember\_s*' ..
2320+
'var d = {func: Legacy}\_s*' ..
2321+
'\d PUSHS "func"\_s*' ..
2322+
'\d PUSHFUNC "Legacy"\_s*' ..
2323+
'\d NEWDICT size 1\_s*' ..
2324+
'\d STORE $0\_s*' ..
2325+
2326+
'var v = d.func()\_s*' ..
2327+
'\d LOAD $0\_s*' ..
2328+
'\d MEMBER func\_s*' ..
2329+
'\d PCALL top (argc 0)\_s*' ..
2330+
'\d PCALL end\_s*' ..
2331+
'\d CLEARDICT\_s*' ..
2332+
'\d\+ STORE $1\_s*' ..
2333+
'\d\+ RETURN void*',
2334+
res)
2335+
enddef
2336+
23052337
def s:EchoMessages()
23062338
echohl ErrorMsg | echom v:exception | echohl NONE
23072339
enddef
@@ -2363,4 +2395,5 @@ def Test_disassemble_after_reload()
23632395
enddef
23642396

23652397

2398+
23662399
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker

src/testdir/test_vim9_func.vim

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2557,6 +2557,37 @@ def Test_legacy_errors()
25572557
endfor
25582558
enddef
25592559

2560+
def Test_call_legacy_with_dict()
2561+
var lines =<< trim END
2562+
vim9script
2563+
func Legacy() dict
2564+
let g:result = self.value
2565+
endfunc
2566+
def TestDirect()
2567+
var d = {value: 'yes', func: Legacy}
2568+
d.func()
2569+
enddef
2570+
TestDirect()
2571+
assert_equal('yes', g:result)
2572+
unlet g:result
2573+
2574+
def TestIndirect()
2575+
var d = {value: 'foo', func: Legacy}
2576+
var Fi = d.func
2577+
Fi()
2578+
enddef
2579+
TestIndirect()
2580+
assert_equal('foo', g:result)
2581+
unlet g:result
2582+
2583+
var d = {value: 'bar', func: Legacy}
2584+
d.func()
2585+
assert_equal('bar', g:result)
2586+
unlet g:result
2587+
END
2588+
CheckScriptSuccess(lines)
2589+
enddef
2590+
25602591
def DoFilterThis(a: string): list<string>
25612592
# closure nested inside another closure using argument
25622593
var Filter = (l) => filter(l, (_, v) => stridx(v, a) == 0)

src/version.c

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

756756
static int included_patches[] =
757757
{ /* Add new patch number below this line */
758+
/**/
759+
3435,
758760
/**/
759761
3434,
760762
/**/

src/vim9.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@ typedef enum {
162162
ISN_CHECKLEN, // check list length is isn_arg.checklen.cl_min_len
163163
ISN_SETTYPE, // set dict type to isn_arg.type.ct_type
164164

165+
ISN_CLEARDICT, // clear dict saved by ISN_MEMBER/ISN_STRINGMEMBER
166+
ISN_USEDICT, // use or clear dict saved by ISN_MEMBER/ISN_STRINGMEMBER
167+
165168
ISN_PUT, // ":put", uses isn_arg.put
166169

167170
ISN_CMDMOD, // set cmdmod

src/vim9compile.c

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2878,9 +2878,10 @@ clear_ppconst(ppconst_T *ppconst)
28782878
/*
28792879
* Compile getting a member from a list/dict/string/blob. Stack has the
28802880
* indexable value and the index or the two indexes of a slice.
2881+
* "keeping_dict" is used for dict[func](arg) to pass dict to func.
28812882
*/
28822883
static int
2883-
compile_member(int is_slice, cctx_T *cctx)
2884+
compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
28842885
{
28852886
type_T **typep;
28862887
garray_T *stack = &cctx->ctx_type_stack;
@@ -2935,6 +2936,8 @@ compile_member(int is_slice, cctx_T *cctx)
29352936
return FAIL;
29362937
if (generate_instr_drop(cctx, ISN_MEMBER, 1) == FAIL)
29372938
return FAIL;
2939+
if (keeping_dict != NULL)
2940+
*keeping_dict = TRUE;
29382941
}
29392942
else if (vartype == VAR_STRING)
29402943
{
@@ -4314,6 +4317,7 @@ compile_subscript(
43144317
ppconst_T *ppconst)
43154318
{
43164319
char_u *name_start = *end_leader;
4320+
int keeping_dict = FALSE;
43174321

43184322
for (;;)
43194323
{
@@ -4360,6 +4364,12 @@ compile_subscript(
43604364
return FAIL;
43614365
if (generate_PCALL(cctx, argcount, name_start, type, TRUE) == FAIL)
43624366
return FAIL;
4367+
if (keeping_dict)
4368+
{
4369+
keeping_dict = FALSE;
4370+
if (generate_instr(cctx, ISN_CLEARDICT) == NULL)
4371+
return FAIL;
4372+
}
43634373
}
43644374
else if (*p == '-' && p[1] == '>')
43654375
{
@@ -4470,6 +4480,12 @@ compile_subscript(
44704480
if (compile_call(arg, p - *arg, cctx, ppconst, 1) == FAIL)
44714481
return FAIL;
44724482
}
4483+
if (keeping_dict)
4484+
{
4485+
keeping_dict = FALSE;
4486+
if (generate_instr(cctx, ISN_CLEARDICT) == NULL)
4487+
return FAIL;
4488+
}
44734489
}
44744490
else if (**arg == '[')
44754491
{
@@ -4537,7 +4553,13 @@ compile_subscript(
45374553
}
45384554
*arg = *arg + 1;
45394555

4540-
if (compile_member(is_slice, cctx) == FAIL)
4556+
if (keeping_dict)
4557+
{
4558+
keeping_dict = FALSE;
4559+
if (generate_instr(cctx, ISN_CLEARDICT) == NULL)
4560+
return FAIL;
4561+
}
4562+
if (compile_member(is_slice, &keeping_dict, cctx) == FAIL)
45414563
return FAIL;
45424564
}
45434565
else if (*p == '.' && p[1] != '.')
@@ -4562,18 +4584,21 @@ compile_subscript(
45624584
semsg(_(e_syntax_error_at_str), *arg);
45634585
return FAIL;
45644586
}
4587+
if (keeping_dict && generate_instr(cctx, ISN_CLEARDICT) == NULL)
4588+
return FAIL;
45654589
if (generate_STRINGMEMBER(cctx, *arg, p - *arg) == FAIL)
45664590
return FAIL;
4591+
keeping_dict = TRUE;
45674592
*arg = p;
45684593
}
45694594
else
45704595
break;
45714596
}
45724597

4573-
// TODO - see handle_subscript():
45744598
// Turn "dict.Func" into a partial for "Func" bound to "dict".
4575-
// Don't do this when "Func" is already a partial that was bound
4576-
// explicitly (pt_auto is FALSE).
4599+
// This needs to be done at runtime to be able to check the type.
4600+
if (keeping_dict && generate_instr(cctx, ISN_USEDICT) == NULL)
4601+
return FAIL;
45774602

45784603
return OK;
45794604
}
@@ -6661,7 +6686,7 @@ compile_load_lhs_with_index(lhs_T *lhs, char_u *var_start, cctx_T *cctx)
66616686
}
66626687

66636688
// Get the member.
6664-
if (compile_member(FALSE, cctx) == FAIL)
6689+
if (compile_member(FALSE, NULL, cctx) == FAIL)
66656690
return FAIL;
66666691
}
66676692
return OK;
@@ -10406,6 +10431,7 @@ delete_instr(isn_T *isn)
1040610431
case ISN_CEXPR_AUCMD:
1040710432
case ISN_CHECKLEN:
1040810433
case ISN_CHECKNR:
10434+
case ISN_CLEARDICT:
1040910435
case ISN_CMDMOD_REV:
1041010436
case ISN_COMPAREANY:
1041110437
case ISN_COMPAREBLOB:
@@ -10482,6 +10508,7 @@ delete_instr(isn_T *isn)
1048210508
case ISN_UNLETINDEX:
1048310509
case ISN_UNLETRANGE:
1048410510
case ISN_UNPACK:
10511+
case ISN_USEDICT:
1048510512
// nothing allocated
1048610513
break;
1048710514
}

0 commit comments

Comments
 (0)