Patch 8.2.2936
Problem: Vim9: converting number to bool uses wrong stack offset. (Salman
Halim)
Solution: Include the offset in the 2BOOL command.
Files: src/vim9compile.c, src/vim9.h, src/vim9execute.c,
src/testdir/test_vim9_expr.vim,
src/testdir/test_vim9_disassemble.vim
*** ../vim-8.2.2935/src/vim9compile.c 2021-06-02 16:47:49.675250216 +0200
--- src/vim9compile.c 2021-06-04 20:44:15.924084665 +0200
***************
*** 577,585 ****
/*
* If type at "offset" isn't already VAR_STRING then generate ISN_2STRING.
* But only for simple types.
*/
static int
! may_generate_2STRING(int offset, cctx_T *cctx)
{
isn_T *isn;
isntype_T isntype = ISN_2STRING;
--- 577,586 ----
/*
* If type at "offset" isn't already VAR_STRING then generate ISN_2STRING.
* But only for simple types.
+ * When "tolerant" is TRUE convert most types to string, e.g. a List.
*/
static int
! may_generate_2STRING(int offset, int tolerant, cctx_T *cctx)
{
isn_T *isn;
isntype_T isntype = ISN_2STRING;
***************
*** 606,617 ****
isntype = ISN_2STRING_ANY;
break;
// conversion not possible
case VAR_VOID:
case VAR_BLOB:
case VAR_FUNC:
case VAR_PARTIAL:
- case VAR_LIST:
case VAR_DICT:
case VAR_JOB:
case VAR_CHANNEL:
--- 607,626 ----
isntype = ISN_2STRING_ANY;
break;
+ // conversion possible when tolerant
+ case VAR_LIST:
+ if (tolerant)
+ {
+ isntype = ISN_2STRING_ANY;
+ break;
+ }
+ // FALLTHROUGH
+
// conversion not possible
case VAR_VOID:
case VAR_BLOB:
case VAR_FUNC:
case VAR_PARTIAL:
case VAR_DICT:
case VAR_JOB:
case VAR_CHANNEL:
***************
*** 623,629 ****
*type = &t_string;
if ((isn = generate_instr(cctx, isntype)) == NULL)
return FAIL;
! isn->isn_arg.number = offset;
return OK;
}
--- 632,639 ----
*type = &t_string;
if ((isn = generate_instr(cctx, isntype)) == NULL)
return FAIL;
! isn->isn_arg.tostring.offset = offset;
! isn->isn_arg.tostring.tolerant = tolerant;
return OK;
}
***************
*** 886,894 ****
/*
* Generate an ISN_2BOOL instruction.
*/
static int
! generate_2BOOL(cctx_T *cctx, int invert)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
--- 896,905 ----
/*
* Generate an ISN_2BOOL instruction.
+ * "offset" is the offset in the type stack.
*/
static int
! generate_2BOOL(cctx_T *cctx, int invert, int offset)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
***************
*** 896,905 ****
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_2BOOL)) == NULL)
return FAIL;
! isn->isn_arg.number = invert;
// type becomes bool
! ((type_T **)stack->ga_data)[stack->ga_len - 1] = &t_bool;
return OK;
}
--- 907,917 ----
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_2BOOL)) == NULL)
return FAIL;
! isn->isn_arg.tobool.invert = invert;
! isn->isn_arg.tobool.offset = offset;
// type becomes bool
! ((type_T **)stack->ga_data)[stack->ga_len + offset] = &t_bool;
return OK;
}
***************
*** 1008,1014 ****
{
// Using "0", "1" or the result of an expression with "&&" or "||" as a
// boolean is OK but requires a conversion.
! generate_2BOOL(cctx, FALSE);
return OK;
}
--- 1020,1026 ----
{
// Using "0", "1" or the result of an expression with "&&" or "||" as a
// boolean is OK but requires a conversion.
! generate_2BOOL(cctx, FALSE, offset);
return OK;
}
***************
*** 2782,2788 ****
return FAIL;
*typep = &t_any;
}
! if (may_generate_2STRING(-1, cctx) == FAIL)
return FAIL;
if (generate_instr_drop(cctx, ISN_MEMBER, 1) == FAIL)
return FAIL;
--- 2794,2800 ----
return FAIL;
*typep = &t_any;
}
! if (may_generate_2STRING(-1, FALSE, cctx) == FAIL)
return FAIL;
if (generate_instr_drop(cctx, ISN_MEMBER, 1) == FAIL)
return FAIL;
***************
*** 3625,3631 ****
}
if (isn->isn_type == ISN_PUSHS)
key = isn->isn_arg.string;
! else if (may_generate_2STRING(-1, cctx) == FAIL)
return FAIL;
*arg = skipwhite(*arg);
if (**arg != ']')
--- 3637,3643 ----
}
if (isn->isn_type == ISN_PUSHS)
key = isn->isn_arg.string;
! else if (may_generate_2STRING(-1, FALSE, cctx) == FAIL)
return FAIL;
*arg = skipwhite(*arg);
if (**arg != ']')
***************
*** 4026,4032 ****
invert = !invert;
--p;
}
! if (generate_2BOOL(cctx, invert) == FAIL)
return FAIL;
}
}
--- 4038,4044 ----
invert = !invert;
--p;
}
! if (generate_2BOOL(cctx, invert, -1) == FAIL)
return FAIL;
}
}
***************
*** 4849,4856 ****
ppconst->pp_is_const = FALSE;
if (*op == '.')
{
! if (may_generate_2STRING(-2, cctx) == FAIL
! || may_generate_2STRING(-1, cctx) == FAIL)
return FAIL;
generate_instr_drop(cctx, ISN_CONCAT, 1);
}
--- 4861,4868 ----
ppconst->pp_is_const = FALSE;
if (*op == '.')
{
! if (may_generate_2STRING(-2, FALSE, cctx) == FAIL
! || may_generate_2STRING(-1, FALSE, cctx) == FAIL)
return FAIL;
generate_instr_drop(cctx, ISN_CONCAT, 1);
}
***************
*** 6420,6426 ****
emsg(e_cannot_use_range_with_dictionary);
return FAIL;
}
! if (dest_type == VAR_DICT && may_generate_2STRING(-1, cctx) == FAIL)
return FAIL;
if (dest_type == VAR_LIST || dest_type == VAR_BLOB)
{
--- 6432,6439 ----
emsg(e_cannot_use_range_with_dictionary);
return FAIL;
}
! if (dest_type == VAR_DICT
! && may_generate_2STRING(-1, FALSE, cctx) == FAIL)
return FAIL;
if (dest_type == VAR_LIST || dest_type == VAR_BLOB)
{
***************
*** 8383,8389 ****
return NULL;
if (cctx->ctx_skip == SKIP_YES)
return p;
! if (may_generate_2STRING(-1, cctx) == FAIL)
return NULL;
if (generate_instr_drop(cctx, ISN_THROW, 1) == NULL)
return NULL;
--- 8396,8402 ----
return NULL;
if (cctx->ctx_skip == SKIP_YES)
return p;
! if (may_generate_2STRING(-1, FALSE, cctx) == FAIL)
return NULL;
if (generate_instr_drop(cctx, ISN_THROW, 1) == NULL)
return NULL;
***************
*** 8618,8624 ****
p += 2;
if (compile_expr0(&p, cctx) == FAIL)
return NULL;
! may_generate_2STRING(-1, cctx);
++count;
p = skipwhite(p);
if (*p != '`')
--- 8631,8637 ----
p += 2;
if (compile_expr0(&p, cctx) == FAIL)
return NULL;
! may_generate_2STRING(-1, TRUE, cctx);
++count;
p = skipwhite(p);
if (*p != '`')
*** ../vim-8.2.2935/src/vim9.h 2021-05-17 00:01:38.807009262 +0200
--- src/vim9.h 2021-06-04 20:37:39.984993250 +0200
***************
*** 148,156 ****
ISN_GETITEM, // push list item, isn_arg.number is the index
ISN_MEMBER, // dict[member]
ISN_STRINGMEMBER, // dict.member using isn_arg.string
! ISN_2BOOL, // falsy/truthy to bool, invert if isn_arg.number
!= 0
ISN_COND2BOOL, // convert value to bool
! ISN_2STRING, // convert value to string at isn_arg.number on stack
ISN_2STRING_ANY, // like ISN_2STRING but check type
ISN_NEGATENR, // apply "-" to number
--- 148,156 ----
ISN_GETITEM, // push list item, isn_arg.number is the index
ISN_MEMBER, // dict[member]
ISN_STRINGMEMBER, // dict.member using isn_arg.string
! ISN_2BOOL, // falsy/truthy to bool, uses isn_arg.tobool
ISN_COND2BOOL, // convert value to bool
! ISN_2STRING, // convert value to string at isn_arg.tostring on stack
ISN_2STRING_ANY, // like ISN_2STRING but check type
ISN_NEGATENR, // apply "-" to number
***************
*** 369,374 ****
--- 369,386 ----
cexprref_T *cexpr_ref;
} cexpr_T;
+ // arguments to ISN_2STRING and ISN_2STRING_ANY
+ typedef struct {
+ int offset;
+ int tolerant;
+ } tostring_T;
+
+ // arguments to ISN_2BOOL
+ typedef struct {
+ int offset;
+ int invert;
+ } tobool_T;
+
/*
* Instruction
*/
***************
*** 414,419 ****
--- 426,433 ----
subs_T subs;
cexpr_T cexpr;
isn_T *instr;
+ tostring_T tostring;
+ tobool_T tobool;
} isn_arg;
};
*** ../vim-8.2.2935/src/vim9execute.c 2021-05-18 17:49:55.372503123 +0200
--- src/vim9execute.c 2021-06-04 20:56:26.130454939 +0200
***************
*** 980,986 ****
* Return FAIL if not allowed.
*/
static int
! do_2string(typval_T *tv, int is_2string_any)
{
if (tv->v_type != VAR_STRING)
{
--- 980,986 ----
* Return FAIL if not allowed.
*/
static int
! do_2string(typval_T *tv, int is_2string_any, int tolerant)
{
if (tv->v_type != VAR_STRING)
{
***************
*** 995,1000 ****
--- 995,1016 ----
case VAR_NUMBER:
case VAR_FLOAT:
case VAR_BLOB: break;
+
+ case VAR_LIST:
+ if (tolerant)
+ {
+ char_u *p;
+
+ str = typval2string(tv, TRUE);
+ clear_tv(tv);
+ tv->v_type = VAR_STRING;
+ tv->vval.v_string = str;
+ // TODO: escaping
+ while ((p = vim_strchr(str, '\n')) != NULL)
+ *p = ' ';
+ return OK;
+ }
+ // FALLTHROUGH
default: to_string_error(tv->v_type);
return FAIL;
}
***************
*** 2055,2061 ****
{
dest_type = tv_dest->v_type;
if (dest_type == VAR_DICT)
! status = do_2string(tv_idx, TRUE);
else if (dest_type == VAR_LIST
&& tv_idx->v_type != VAR_NUMBER)
{
--- 2071,2077 ----
{
dest_type = tv_dest->v_type;
if (dest_type == VAR_DICT)
! status = do_2string(tv_idx, TRUE, FALSE);
else if (dest_type == VAR_LIST
&& tv_idx->v_type != VAR_NUMBER)
{
***************
*** 3770,3784 ****
int n;
int error = FALSE;
- tv = STACK_TV_BOT(-1);
if (iptr->isn_type == ISN_2BOOL)
{
n = tv2bool(tv);
! if (iptr->isn_arg.number) // invert
n = !n;
}
else
{
SOURCING_LNUM = iptr->isn_lnum;
n = tv_get_bool_chk(tv, &error);
if (error)
--- 3786,3801 ----
int n;
int error = FALSE;
if (iptr->isn_type == ISN_2BOOL)
{
+ tv = STACK_TV_BOT(iptr->isn_arg.tobool.offset);
n = tv2bool(tv);
! if (iptr->isn_arg.tobool.invert)
n = !n;
}
else
{
+ tv = STACK_TV_BOT(-1);
SOURCING_LNUM = iptr->isn_lnum;
n = tv_get_bool_chk(tv, &error);
if (error)
***************
*** 3793,3800 ****
case ISN_2STRING:
case ISN_2STRING_ANY:
SOURCING_LNUM = iptr->isn_lnum;
! if (do_2string(STACK_TV_BOT(iptr->isn_arg.number),
! iptr->isn_type == ISN_2STRING_ANY) == FAIL)
goto on_error;
break;
--- 3810,3818 ----
case ISN_2STRING:
case ISN_2STRING_ANY:
SOURCING_LNUM = iptr->isn_lnum;
! if (do_2string(STACK_TV_BOT(iptr->isn_arg.tostring.offset),
! iptr->isn_type == ISN_2STRING_ANY,
! iptr->isn_arg.tostring.tolerant) == FAIL)
goto on_error;
break;
***************
*** 5122,5147 ****
break;
}
case ISN_COND2BOOL: smsg("%s%4d COND2BOOL", pfx, current); break;
! case ISN_2BOOL: if (iptr->isn_arg.number)
! smsg("%s%4d INVERT (!val)", pfx, current);
else
! smsg("%s%4d 2BOOL (!!val)", pfx, current);
break;
case ISN_2STRING: smsg("%s%4d 2STRING stack[%lld]", pfx, current,
! (varnumber_T)(iptr->isn_arg.number));
break;
! case ISN_2STRING_ANY: smsg("%s%4d 2STRING_ANY stack[%lld]", pfx,
current,
! (varnumber_T)(iptr->isn_arg.number));
break;
! case ISN_RANGE: smsg("%s%4d RANGE %s", pfx, current,
iptr->isn_arg.string);
break;
case ISN_PUT:
if (iptr->isn_arg.put.put_lnum == LNUM_VARIABLE_RANGE_ABOVE)
smsg("%s%4d PUT %c above range",
! pfx, current,
iptr->isn_arg.put.put_regname);
else if (iptr->isn_arg.put.put_lnum == LNUM_VARIABLE_RANGE)
smsg("%s%4d PUT %c range",
! pfx, current,
iptr->isn_arg.put.put_regname);
else
smsg("%s%4d PUT %c %ld", pfx, current,
iptr->isn_arg.put.put_regname,
--- 5140,5169 ----
break;
}
case ISN_COND2BOOL: smsg("%s%4d COND2BOOL", pfx, current); break;
! case ISN_2BOOL: if (iptr->isn_arg.tobool.invert)
! smsg("%s%4d INVERT %d (!val)", pfx, current,
! iptr->isn_arg.tobool.offset);
else
! smsg("%s%4d 2BOOL %d (!!val)", pfx, current,
! iptr->isn_arg.tobool.offset);
break;
case ISN_2STRING: smsg("%s%4d 2STRING stack[%lld]", pfx, current,
! (varnumber_T)(iptr->isn_arg.tostring.offset));
break;
! case ISN_2STRING_ANY: smsg("%s%4d 2STRING_ANY stack[%lld]",
! pfx, current,
! (varnumber_T)(iptr->isn_arg.tostring.offset));
break;
! case ISN_RANGE: smsg("%s%4d RANGE %s", pfx, current,
! iptr->isn_arg.string);
break;
case ISN_PUT:
if (iptr->isn_arg.put.put_lnum == LNUM_VARIABLE_RANGE_ABOVE)
smsg("%s%4d PUT %c above range",
! pfx, current, iptr->isn_arg.put.put_regname);
else if (iptr->isn_arg.put.put_lnum == LNUM_VARIABLE_RANGE)
smsg("%s%4d PUT %c range",
! pfx, current, iptr->isn_arg.put.put_regname);
else
smsg("%s%4d PUT %c %ld", pfx, current,
iptr->isn_arg.put.put_regname,
*** ../vim-8.2.2935/src/testdir/test_vim9_expr.vim 2021-05-28
17:52:36.908197725 +0200
--- src/testdir/test_vim9_expr.vim 2021-06-04 20:45:13.759948282 +0200
***************
*** 2480,2485 ****
--- 2480,2504 ----
endif
enddef
+ def Test_expr7_call_2bool()
+ var lines =<< trim END
+ vim9script
+
+ def BrokenCall(nr: number, mode: bool, use: string): void
+ assert_equal(3, nr)
+ assert_equal(false, mode)
+ assert_equal('ab', use)
+ enddef
+
+ def TestBrokenCall(): void
+ BrokenCall(3, 0, 'ab')
+ enddef
+
+ TestBrokenCall()
+ END
+ CheckScriptSuccess(lines)
+ enddef
+
let g:oneString = 'one'
def Test_expr_member()
*** ../vim-8.2.2935/src/testdir/test_vim9_disassemble.vim 2021-05-07
17:55:51.979584412 +0200
--- src/testdir/test_vim9_disassemble.vim 2021-06-04 20:56:49.430440655
+0200
***************
*** 1650,1660 ****
'\d STORE $0\_s*' ..
'var invert = !flag\_s*' ..
'\d LOAD $0\_s*' ..
! '\d INVERT (!val)\_s*' ..
'\d STORE $1\_s*' ..
'var res = !!flag\_s*' ..
'\d LOAD $0\_s*' ..
! '\d 2BOOL (!!val)\_s*' ..
'\d STORE $2\_s*',
instr)
assert_equal(true, InvertBool())
--- 1650,1660 ----
'\d STORE $0\_s*' ..
'var invert = !flag\_s*' ..
'\d LOAD $0\_s*' ..
! '\d INVERT -1 (!val)\_s*' ..
'\d STORE $1\_s*' ..
'var res = !!flag\_s*' ..
'\d LOAD $0\_s*' ..
! '\d 2BOOL -1 (!!val)\_s*' ..
'\d STORE $2\_s*',
instr)
assert_equal(true, InvertBool())
*** ../vim-8.2.2935/src/version.c 2021-06-04 19:17:03.645562505 +0200
--- src/version.c 2021-06-04 20:36:28.641150342 +0200
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 2936,
/**/
--
FROG: How you English say: I one more time, mac, I unclog my nose towards
you, sons of a window-dresser, so, you think you could out-clever us
French fellows with your silly knees-bent creeping about advancing
behaviour. (blows a raspberry) I wave my private parts at your aunties,
you brightly-coloured, mealy-templed, cranberry-smelling, electric
donkey-bottom biters.
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/vim_dev/202106041901.154J16Tx3183376%40masaka.moolenaar.net.