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 -- [email protected] -- 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    ///

-- 
-- 
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/202009092028.089KSRop435748%40masaka.moolenaar.net.

Raspunde prin e-mail lui