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.

Raspunde prin e-mail lui