Patch 8.2.1650
Problem: Vim9: result of && and || expression cannot be assigned to a bool
at the script level.
Solution: Add the VAR_BOOL_OK flag. Convert to bool when needed.
Files: src/structs.h, src/vim9type.c, src/proto/
vim9type.pro,
src/vim9script.c, src/evalvars.c, src/eval.c,
src/testdir/test_vim9_script.vim
*** ../vim-8.2.1649/src/structs.h 2020-09-09 14:55:28.155619452 +0200
--- src/structs.h 2020-09-09 21:02:59.711923017 +0200
***************
*** 1381,1387 ****
typedef struct
{
vartype_T v_type;
! char v_lock; // see below: VAR_LOCKED, VAR_FIXED
union
{
varnumber_T v_number; // number value
--- 1381,1387 ----
typedef struct
{
vartype_T v_type;
! char v_lock; // see below: VAR_LOCKED, VAR_FIXED, VAR_BOOL_OK
union
{
varnumber_T v_number; // number value
***************
*** 1406,1413 ****
// allowed to mask existing functions
// Values for "v_lock".
! #define VAR_LOCKED 1 // locked with lock(), can use unlock()
! #define VAR_FIXED 2 // locked forever
/*
* Structure to hold an item of a list: an internal variable without a name.
--- 1406,1414 ----
// allowed to mask existing functions
// Values for "v_lock".
! #define VAR_LOCKED 1 // locked with lock(), can use unlock()
! #define VAR_FIXED 2 // locked forever
! #define VAR_BOOL_OK 4 // can be convered to bool
/*
* Structure to hold an item of a list: an internal variable without a name.
*** ../vim-8.2.1649/src/vim9type.c 2020-09-09 18:54:39.166253632 +0200
--- src/vim9type.c 2020-09-09 22:08:14.645369292 +0200
***************
*** 199,226 ****
* Get a type_T for a typval_T.
* "type_list" is used to temporarily create types in.
*/
! type_T *
! typval2type(typval_T *tv, garray_T *type_gap)
{
type_T *type;
type_T *member_type;
if (tv->v_type == VAR_NUMBER)
- {
- if (tv->vval.v_number == 0 || tv->vval.v_number == 1)
- {
- // number 0 and 1 can also be used for bool
- type = alloc_type(type_gap);
- if (type == NULL)
- return NULL;
- type->tt_type = VAR_NUMBER;
- type->tt_flags = TTFLAG_BOOL_OK;
- return type;
- }
return &t_number;
- }
if (tv->v_type == VAR_BOOL)
! return &t_bool; // not used
if (tv->v_type == VAR_STRING)
return &t_string;
--- 199,214 ----
* Get a type_T for a typval_T.
* "type_list" is used to temporarily create types in.
*/
! static type_T *
! typval2type_int(typval_T *tv, garray_T *type_gap)
{
type_T *type;
type_T *member_type;
if (tv->v_type == VAR_NUMBER)
return &t_number;
if (tv->v_type == VAR_BOOL)
! return &t_bool;
if (tv->v_type == VAR_STRING)
return &t_string;
***************
*** 298,303 ****
--- 286,331 ----
}
/*
+ * Return TRUE if "tv" is not a bool but should be converted to bool.
+ */
+ int
+ need_convert_to_bool(type_T *type, typval_T *tv)
+ {
+ return type != NULL && type == &t_bool && tv->v_type != VAR_BOOL
+ && ((tv->v_lock & VAR_BOOL_OK)
+ || (tv->v_type == VAR_NUMBER
+ && (tv->vval.v_number == 0 || tv->vval.v_number == 1)));
+ }
+
+ /*
+ * Get a type_T for a typval_T and handle VAR_BOOL_OK.
+ * "type_list" is used to temporarily create types in.
+ */
+ type_T *
+ typval2type(typval_T *tv, garray_T *type_gap)
+ {
+ type_T *type = typval2type_int(tv, type_gap);
+
+ if (type != NULL && type != &t_bool
+ && ((tv->v_type == VAR_NUMBER
+ && (tv->vval.v_number == 0 || tv->vval.v_number == 1))
+ || (tv->v_lock & VAR_BOOL_OK)))
+ {
+ type_T *newtype = alloc_type(type_gap);
+
+ // Number 0 and 1 and expression with "&&" or "||" can also be used
+ // for bool.
+ if (newtype != NULL)
+ {
+ *newtype = *type;
+ newtype->tt_flags = TTFLAG_BOOL_OK;
+ type = newtype;
+ }
+ }
+ return type;
+ }
+
+ /*
* Get a type_T for a typval_T, used for v: variables.
* "type_list" is used to temporarily create types in.
*/
***************
*** 371,377 ****
{
if (expected->tt_type != actual->tt_type)
{
! if (expected->tt_type == VAR_BOOL && actual->tt_type == VAR_NUMBER
&& (actual->tt_flags & TTFLAG_BOOL_OK))
// Using number 0 or 1 for bool is OK.
return OK;
--- 399,405 ----
{
if (expected->tt_type != actual->tt_type)
{
! if (expected->tt_type == VAR_BOOL
&& (actual->tt_flags & TTFLAG_BOOL_OK))
// Using number 0 or 1 for bool is OK.
return OK;
*** ../vim-8.2.1649/src/proto/
vim9type.pro 2020-09-09 14:55:28.155619452 +0200
--- src/proto/
vim9type.pro 2020-09-09 22:01:40.354479772 +0200
***************
*** 6,11 ****
--- 6,12 ----
type_T *alloc_func_type(type_T *ret_type, int argcount, garray_T *type_gap);
type_T *get_func_type(type_T *ret_type, int argcount, garray_T *type_gap);
int func_type_add_arg_types(type_T *functype, int argcount, garray_T *type_gap);
+ int need_convert_to_bool(type_T *type, typval_T *tv);
type_T *typval2type(typval_T *tv, garray_T *type_gap);
type_T *typval2type_vimvar(typval_T *tv, garray_T *type_gap);
int check_typval_type(type_T *expected, typval_T *actual_tv, int argidx);
*** ../vim-8.2.1649/src/vim9script.c 2020-08-30 23:24:17.219401371 +0200
--- src/vim9script.c 2020-09-09 22:03:24.430189254 +0200
***************
*** 557,562 ****
--- 557,563 ----
/*
* Check if the type of script variable "dest" allows assigning "value".
+ * If needed convert "value" to a bool.
*/
int
check_script_var_type(typval_T *dest, typval_T *value, char_u *name)
***************
*** 575,586 ****
if (sv->sv_tv == dest)
{
if (sv->sv_const)
{
semsg(_(e_readonlyvar), name);
return FAIL;
}
! return check_typval_type(sv->sv_type, value, 0);
}
}
iemsg("check_script_var_type(): not found");
--- 576,599 ----
if (sv->sv_tv == dest)
{
+ int ret;
+
if (sv->sv_const)
{
semsg(_(e_readonlyvar), name);
return FAIL;
}
! ret = check_typval_type(sv->sv_type, value, 0);
! if (ret == OK && need_convert_to_bool(sv->sv_type, value))
! {
! int val = tv2bool(value);
!
! clear_tv(value);
! value->v_type = VAR_BOOL;
! value->v_lock = 0;
! value->vval.v_number = val ? VVAL_TRUE : VVAL_FALSE;
! }
! return ret;
}
}
iemsg("check_script_var_type(): not found");
*** ../vim-8.2.1649/src/evalvars.c 2020-09-01 23:16:27.451424408 +0200
--- src/evalvars.c 2020-09-09 22:21:58.622704739 +0200
***************
*** 778,784 ****
evalarg_T evalarg;
int len = 1;
! rettv.v_type = VAR_UNKNOWN;
i = FAIL;
if (has_assign || concat)
{
--- 778,784 ----
evalarg_T evalarg;
int len = 1;
! CLEAR_FIELD(rettv);
i = FAIL;
if (has_assign || concat)
{
***************
*** 2935,2944 ****
set_var_const(
char_u *name,
type_T *type,
! typval_T *tv,
int copy, // make copy of value in "tv"
int flags) // LET_IS_CONST and/or LET_NO_COMMAND
{
dictitem_T *di;
char_u *varname;
hashtab_T *ht;
--- 2935,2946 ----
set_var_const(
char_u *name,
type_T *type,
! typval_T *tv_arg,
int copy, // make copy of value in "tv"
int flags) // LET_IS_CONST and/or LET_NO_COMMAND
{
+ typval_T *tv = tv_arg;
+ typval_T bool_tv;
dictitem_T *di;
char_u *varname;
hashtab_T *ht;
***************
*** 2971,2976 ****
--- 2973,2987 ----
&& var_wrong_func_name(name, di == NULL))
return;
+ if (need_convert_to_bool(type, tv))
+ {
+ // Destination is a bool and the value is not, but it can be converted.
+ CLEAR_FIELD(bool_tv);
+ bool_tv.v_type = VAR_BOOL;
+ bool_tv.vval.v_number = tv2bool(tv) ? VVAL_TRUE : VVAL_FALSE;
+ tv = &bool_tv;
+ }
+
if (di != NULL)
{
if ((di->di_flags & DI_FLAGS_RELOAD) == 0)
***************
*** 2989,2995 ****
return;
}
! // check the type
if (check_script_var_type(&di->di_tv, tv, name) == FAIL)
return;
}
--- 3000,3006 ----
return;
}
! // check the type and adjust to bool if needed
if (check_script_var_type(&di->di_tv, tv, name) == FAIL)
return;
}
*** ../vim-8.2.1649/src/eval.c 2020-09-01 19:56:10.928571016 +0200
--- src/eval.c 2020-09-09 21:46:58.424753261 +0200
***************
*** 2356,2361 ****
--- 2356,2364 ----
clear_evalarg(&local_evalarg, NULL);
else
evalarg->eval_flags = orig_flags;
+
+ // Resulting value can be assigned to a bool.
+ rettv->v_lock |= VAR_BOOL_OK;
}
return OK;
***************
*** 2451,2456 ****
--- 2454,2460 ----
*arg = skipwhite_and_linebreak(*arg + 2, evalarg_used);
evalarg_used->eval_flags = result ? orig_flags
: orig_flags & ~EVAL_EVALUATE;
+ CLEAR_FIELD(var2);
if (eval4(arg, &var2, evalarg_used) == FAIL)
return FAIL;
***************
*** 2487,2492 ****
--- 2491,2499 ----
clear_evalarg(&local_evalarg, NULL);
else
evalarg->eval_flags = orig_flags;
+
+ // Resulting value can be assigned to a bool.
+ rettv->v_lock |= VAR_BOOL_OK;
}
return OK;
*** ../vim-8.2.1649/src/testdir/test_vim9_script.vim 2020-09-09 20:03:42.908661678 +0200
--- src/testdir/test_vim9_script.vim 2020-09-09 22:24:45.102151701 +0200
***************
*** 66,78 ****
let flag: bool = GetFlag()
assert_equal(true, flag)
flag = 0
! # assert_equal(false, flag)
flag = 1
! # assert_equal(true, flag)
! # flag = 99 || 123
! # assert_equal(true, flag)
! # flag = 'yes' && []
! # assert_equal(false, flag)
END
CheckScriptSuccess(lines)
CheckDefAndScriptFailure(['let x: bool = 2'], 'E1012:')
--- 66,78 ----
let flag: bool = GetFlag()
assert_equal(true, flag)
flag = 0
! assert_equal(false, flag)
flag = 1
! assert_equal(true, flag)
! flag = 99 || 123
! assert_equal(true, flag)
! flag = 'yes' && []
! assert_equal(false, flag)
END
CheckScriptSuccess(lines)
CheckDefAndScriptFailure(['let x: bool = 2'], 'E1012:')
*** ../vim-8.2.1649/src/version.c 2020-09-09 20:58:52.008764176 +0200
--- src/version.c 2020-09-09 21:25:14.440335273 +0200
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 1650,
/**/
--
User: I'm having problems with my text editor.
Help desk: Which editor are you using?
User: I don't know, but it's version VI (pronounced: 6).
Help desk: Oh, then you should upgrade to version VIM (pronounced: 994).
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language --
http://www.Zimbu.org ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///