Patch 8.2.1795
Problem:    Vim9: operators && and || have a confusing result.
Solution:   Make the result a boolean.
Files:      runtime/doc/vim9.txt, src/eval.c, src/vim9compile.c,
            src/vim9execute.c, src/vim9type.c, src/structs.h, src/vim9.h,
            src/testdir/test_vim9_expr.vim, src/testdir/test_vim9_assign.vim,
            src/testdir/test_vim9_cmd.vim,
            src/testdir/test_vim9_disassemble.vim


*** ../vim-8.2.1794/runtime/doc/vim9.txt        2020-09-26 15:08:52.877779920 
+0200
--- runtime/doc/vim9.txt        2020-10-03 22:48:15.127287808 +0200
***************
*** 65,70 ****
--- 65,99 ----
  
  THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
  
+ Overview ~
+ 
+ Brief summary of the differences you will most often encounter when using Vim9
+ script and `:def` functions; details are below:
+ - Comments start with #, not ": >
+       echo "hello"   # comment
+ - Using a backslash for line continuation is hardly ever needed: >
+       echo "hello "
+            .. yourName
+            .. ", how are you?"
+ - White space is required in many places.
+ - Assign values without `:let`, declare variables with `:var`: >
+       var count = 0
+       count += 3
+ - Constants can be declared with `:final` and `:const`: >
+       final matches = []                # add matches
+       const names = ['Betty', 'Peter']  # cannot be changed
+ - `:final` cannot be used as an abbreviation of `:finally`.
+ - Variables and functions are script-local by default.
+ - Functions are declared with argument types and return type: >
+       def CallMe(count: number, message: string): bool
+ - Call functions without `:call`: >
+       writefile(['done'], 'file.txt')
+ - You cannot use `:xit`, `:t`, `:append`, `:change`, `:insert` or curly-braces
+   names.
+ - A range before a command must be prefixed with a colon: >
+       :%s/this/that
+ 
+ 
  Comments starting with # ~
  
  In legacy Vim script comments start with double quote.  In Vim9 script
***************
*** 125,149 ****
                                                        *vim9-scopes*
  When using `:function` or `:def` to specify a new function at the script level
  in a Vim9 script, the function is local to the script, as if "s:" was
! prefixed.  Using the "s:" prefix is optional.  To define or use a global
! function or variable the "g:" prefix should be used.  For functions in an
! autoload script the "name#" prefix is sufficient. >
        def ThisFunction()          # script-local
        def s:ThisFunction()        # script-local
        def g:ThatFunction()        # global
-       def ThatFunction()          # global if no local ThatFunction()
        def scriptname#function()   # autoload
  
! When using `:function` or `:def` to specify a new function inside a function,
! the function is local to the function.  It is not possible to define a
! script-local function inside a function. It is possible to define a global
! function, using the "g:" prefix.
  
  When referring to a function and no "s:" or "g:" prefix is used, Vim will
  prefer using a local function (in the function scope, script scope or
! imported) before looking for a global function.
! In all cases the function must be defined before used.  That is when it is
! first called or when `:defcompile` causes the call to be compiled.
  
  The result is that functions and variables without a namespace can usually be
  found in the script, either defined there or imported.  Global functions and
--- 154,178 ----
                                                        *vim9-scopes*
  When using `:function` or `:def` to specify a new function at the script level
  in a Vim9 script, the function is local to the script, as if "s:" was
! prefixed.  Using the "s:" prefix is optional.  To define a global function or
! variable the "g:" prefix must be used.  For functions in an autoload script
! the "name#" prefix is sufficient. >
        def ThisFunction()          # script-local
        def s:ThisFunction()        # script-local
        def g:ThatFunction()        # global
        def scriptname#function()   # autoload
  
! When using `:function` or `:def` to specify a nested function inside a `:def`
! function, this nested function is local to the code block it is defined in.
! In a `:def` function IT is not possible to define a script-local function.  it
! is possible to define a global function by using the "g:" prefix.
  
  When referring to a function and no "s:" or "g:" prefix is used, Vim will
  prefer using a local function (in the function scope, script scope or
! imported) before looking for a global function.  However, it is recommended to
! always use "g:" to refer to a local function for clarity.  In all cases the
! function must be defined before used.  That is when it is first called or when
! `:defcompile` causes the call to be compiled.
  
  The result is that functions and variables without a namespace can usually be
  found in the script, either defined there or imported.  Global functions and
***************
*** 155,161 ****
  
  
  Variable declarations with :var, :final and :const ~
!                                                       *vim9-declaration*
  Local variables need to be declared with `:var`.  Local constants need to be
  declared with `:final` or `:const`.  We refer to both as "variables" in this
  section.
--- 184,190 ----
  
  
  Variable declarations with :var, :final and :const ~
!                                               *vim9-declaration* *:var*
  Local variables need to be declared with `:var`.  Local constants need to be
  declared with `:final` or `:const`.  We refer to both as "variables" in this
  section.
***************
*** 232,238 ****
        myList = [3, 4]         # Error!
        myList[0] = 9           # Error!
        muList->add(3)          # Error!
! 
  `:final` is used for making only the variable a constant, the value can be
  changed.  This is well known from Java.  Example: >
        final myList = [1, 2]
--- 261,267 ----
        myList = [3, 4]         # Error!
        myList[0] = 9           # Error!
        muList->add(3)          # Error!
! <                                                     *:final*
  `:final` is used for making only the variable a constant, the value can be
  changed.  This is well known from Java.  Example: >
        final myList = [1, 2]
***************
*** 442,451 ****
  difference is made where JavaScript does not work like most people expect.
  Specifically, an empty list is falsy.
  
- Any type of variable can be used as a condition, there is no error, not even
- for using a list or job.  This is very much like JavaScript, but there are a
- few exceptions.
- 
        type            TRUE when ~
        bool            v:true or 1
        number          non-zero
--- 471,476 ----
***************
*** 461,477 ****
        class           when not NULL
        object          when not NULL (TODO: when isTrue() returns v:true)
  
! The boolean operators "||" and "&&" do not change the value: >
!       8 || 2   == 8
!       0 || 2   == 2
!       0 || ''  == ''
!       8 && 2   == 2
!       0 && 2   == 0
!       2 && 0   == 0
!       [] && 2  == []
  
! When using `..` for string concatenation arguments of simple types are always
! converted to string. >
        'hello ' .. 123  == 'hello 123'
        'hello ' .. v:true  == 'hello v:true'
  
--- 486,510 ----
        class           when not NULL
        object          when not NULL (TODO: when isTrue() returns v:true)
  
! The boolean operators "||" and "&&" expect the values to be boolean, zero or
! one: >
!       1 || false   == true
!       0 || 1       == true
!       0 || false   == false
!       1 && true    == true
!       0 && 1       == false
!       8 || 0       Error!
!       'yes' && 0   Error!
!       [] || 99     Error!
! 
! When using "!" for inverting, there is no error for using any type and the
! result is a boolean: >
!       !'yes'                  == false
!       var myList = [1, 2, 3]
!       !!myList                == true
  
! When using "`.."` for string concatenation arguments of simple types are
! always converted to string. >
        'hello ' .. 123  == 'hello 123'
        'hello ' .. v:true  == 'hello v:true'
  
*** ../vim-8.2.1794/src/eval.c  2020-10-03 20:16:48.771216676 +0200
--- src/eval.c  2020-10-03 21:11:38.013436158 +0200
***************
*** 2296,2302 ****
        int         orig_flags;
        long        result = FALSE;
        typval_T    var2;
!       int         error;
        int         vim9script = in_vim9script();
  
        if (evalarg == NULL)
--- 2296,2302 ----
        int         orig_flags;
        long        result = FALSE;
        typval_T    var2;
!       int         error = FALSE;
        int         vim9script = in_vim9script();
  
        if (evalarg == NULL)
***************
*** 2309,2326 ****
        if (evaluate)
        {
            if (vim9script)
!           {
!               result = tv2bool(rettv);
!           }
!           else
!           {
!               error = FALSE;
!               if (tv_get_number_chk(rettv, &error) != 0)
!                   result = TRUE;
!               clear_tv(rettv);
!               if (error)
!                   return FAIL;
!           }
        }
  
        /*
--- 2309,2320 ----
        if (evaluate)
        {
            if (vim9script)
!               result = tv_get_bool_chk(rettv, &error);
!           else if (tv_get_number_chk(rettv, &error) != 0)
!               result = TRUE;
!           clear_tv(rettv);
!           if (error)
!               return FAIL;
        }
  
        /*
***************
*** 2362,2386 ****
            if (evaluate && !result)
            {
                if (vim9script)
                {
!                   clear_tv(rettv);
!                   *rettv = var2;
!                   result = tv2bool(rettv);
                }
                else
                {
!                   if (tv_get_number_chk(&var2, &error) != 0)
!                       result = TRUE;
!                   clear_tv(&var2);
!                   if (error)
!                       return FAIL;
                }
            }
-           if (evaluate && !vim9script)
-           {
-               rettv->v_type = VAR_NUMBER;
-               rettv->vval.v_number = result;
-           }
  
            p = eval_next_non_blank(*arg, evalarg_used, &getnext);
        }
--- 2356,2381 ----
            if (evaluate && !result)
            {
                if (vim9script)
+                   result = tv_get_bool_chk(&var2, &error);
+               else if (tv_get_number_chk(&var2, &error) != 0)
+                   result = TRUE;
+               clear_tv(&var2);
+               if (error)
+                   return FAIL;
+           }
+           if (evaluate)
+           {
+               if (vim9script)
                {
!                   rettv->v_type = VAR_BOOL;
!                   rettv->vval.v_number = result ? VVAL_TRUE : VVAL_FALSE;
                }
                else
                {
!                   rettv->v_type = VAR_NUMBER;
!                   rettv->vval.v_number = result;
                }
            }
  
            p = eval_next_non_blank(*arg, evalarg_used, &getnext);
        }
***************
*** 2389,2397 ****
            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;
--- 2384,2389 ----
***************
*** 2430,2436 ****
        int         evaluate;
        long        result = TRUE;
        typval_T    var2;
!       int         error;
        int         vim9script = in_vim9script();
  
        if (evalarg == NULL)
--- 2422,2428 ----
        int         evaluate;
        long        result = TRUE;
        typval_T    var2;
!       int         error = FALSE;
        int         vim9script = in_vim9script();
  
        if (evalarg == NULL)
***************
*** 2443,2460 ****
        if (evaluate)
        {
            if (vim9script)
!           {
!               result = tv2bool(rettv);
!           }
!           else
!           {
!               error = FALSE;
!               if (tv_get_number_chk(rettv, &error) == 0)
!                   result = FALSE;
!               clear_tv(rettv);
!               if (error)
!                   return FAIL;
!           }
        }
  
        /*
--- 2435,2446 ----
        if (evaluate)
        {
            if (vim9script)
!               result = tv_get_bool_chk(rettv, &error);
!           else if (tv_get_number_chk(rettv, &error) == 0)
!               result = FALSE;
!           clear_tv(rettv);
!           if (error)
!               return FAIL;
        }
  
        /*
***************
*** 2466,2472 ****
                *arg = eval_next_line(evalarg_used);
            else
            {
!               if (evaluate && in_vim9script() && !VIM_ISWHITE(p[-1]))
                {
                    error_white_both(p, 2);
                    clear_tv(rettv);
--- 2452,2458 ----
                *arg = eval_next_line(evalarg_used);
            else
            {
!               if (evaluate && vim9script && !VIM_ISWHITE(p[-1]))
                {
                    error_white_both(p, 2);
                    clear_tv(rettv);
***************
*** 2497,2521 ****
            if (evaluate && result)
            {
                if (vim9script)
                {
!                   clear_tv(rettv);
!                   *rettv = var2;
!                   result = tv2bool(rettv);
                }
                else
                {
!                   if (tv_get_number_chk(&var2, &error) == 0)
!                       result = FALSE;
!                   clear_tv(&var2);
!                   if (error)
!                       return FAIL;
                }
            }
-           if (evaluate && !vim9script)
-           {
-               rettv->v_type = VAR_NUMBER;
-               rettv->vval.v_number = result;
-           }
  
            p = eval_next_non_blank(*arg, evalarg_used, &getnext);
        }
--- 2483,2508 ----
            if (evaluate && result)
            {
                if (vim9script)
+                   result = tv_get_bool_chk(&var2, &error);
+               else if (tv_get_number_chk(&var2, &error) == 0)
+                   result = FALSE;
+               clear_tv(&var2);
+               if (error)
+                   return FAIL;
+           }
+           if (evaluate)
+           {
+               if (vim9script)
                {
!                   rettv->v_type = VAR_BOOL;
!                   rettv->vval.v_number = result ? VVAL_TRUE : VVAL_FALSE;
                }
                else
                {
!                   rettv->v_type = VAR_NUMBER;
!                   rettv->vval.v_number = result;
                }
            }
  
            p = eval_next_non_blank(*arg, evalarg_used, &getnext);
        }
***************
*** 2524,2532 ****
            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;
--- 2511,2516 ----
*** ../vim-8.2.1794/src/vim9compile.c   2020-10-03 20:16:48.775216665 +0200
--- src/vim9compile.c   2020-10-03 22:24:36.363524418 +0200
***************
*** 706,711 ****
--- 706,730 ----
      return OK;
  }
  
+ /*
+  * Generate an ISN_COND2BOOL instruction.
+  */
+     static int
+ generate_COND2BOOL(cctx_T *cctx)
+ {
+     isn_T     *isn;
+     garray_T  *stack = &cctx->ctx_type_stack;
+ 
+     RETURN_OK_IF_SKIP(cctx);
+     if ((isn = generate_instr(cctx, ISN_COND2BOOL)) == NULL)
+       return FAIL;
+ 
+     // type becomes bool
+     ((type_T **)stack->ga_data)[stack->ga_len - 1] = &t_bool;
+ 
+     return OK;
+ }
+ 
      static int
  generate_TYPECHECK(
        cctx_T      *cctx,
***************
*** 4003,4009 ****
        garray_T        *instr = &cctx->ctx_instr;
        garray_T        end_ga;
        garray_T        *stack = &cctx->ctx_type_stack;
!       type_T          **typep;
  
        /*
         * Repeat until there is no following "||" or "&&"
--- 4022,4028 ----
        garray_T        *instr = &cctx->ctx_instr;
        garray_T        end_ga;
        garray_T        *stack = &cctx->ctx_type_stack;
!       int             all_bool_values = TRUE;
  
        /*
         * Repeat until there is no following "||" or "&&"
***************
*** 4023,4031 ****
                return FAIL;
            }
  
!           // TODO: use ppconst if the value is a constant
            generate_ppconst(cctx, ppconst);
  
            if (ga_grow(&end_ga, 1) == FAIL)
            {
                ga_clear(&end_ga);
--- 4042,4054 ----
                return FAIL;
            }
  
!           // TODO: use ppconst if the value is a constant and check
!           // evaluating to bool
            generate_ppconst(cctx, ppconst);
  
+           if (((type_T **)stack->ga_data)[stack->ga_len - 1] != &t_bool)
+               all_bool_values = FALSE;
+ 
            if (ga_grow(&end_ga, 1) == FAIL)
            {
                ga_clear(&end_ga);
***************
*** 4034,4040 ****
            *(((int *)end_ga.ga_data) + end_ga.ga_len) = instr->ga_len;
            ++end_ga.ga_len;
            generate_JUMP(cctx, opchar == '|'
!                        ?  JUMP_AND_KEEP_IF_TRUE : JUMP_AND_KEEP_IF_FALSE, 0);
  
            // eval the next expression
            *arg = skipwhite(p + 2);
--- 4057,4063 ----
            *(((int *)end_ga.ga_data) + end_ga.ga_len) = instr->ga_len;
            ++end_ga.ga_len;
            generate_JUMP(cctx, opchar == '|'
!                                ?  JUMP_IF_COND_TRUE : JUMP_IF_COND_FALSE, 0);
  
            // eval the next expression
            *arg = skipwhite(p + 2);
***************
*** 4064,4082 ****
        }
        ga_clear(&end_ga);
  
!       // The resulting type can be used as a bool.
!       typep = ((type_T **)stack->ga_data) + stack->ga_len - 1;
!       if (*typep != &t_bool)
!       {
!           type_T *type = get_type_ptr(cctx->ctx_type_list);
! 
!           if (type != NULL)
!           {
!               *type = **typep;
!               type->tt_flags |= TTFLAG_BOOL_OK;
!               *typep = type;
!           }
!       }
      }
  
      return OK;
--- 4087,4095 ----
        }
        ga_clear(&end_ga);
  
!       // The resulting type is converted to bool if needed.
!       if (!all_bool_values)
!           generate_COND2BOOL(cctx);
      }
  
      return OK;
***************
*** 4087,4096 ****
   *
   * Produces instructions:
   *    EVAL expr4a             Push result of "expr4a"
!  *    JUMP_AND_KEEP_IF_FALSE end
   *    EVAL expr4b             Push result of "expr4b"
!  *    JUMP_AND_KEEP_IF_FALSE end
   *    EVAL expr4c             Push result of "expr4c"
   * end:
   */
      static int
--- 4100,4110 ----
   *
   * Produces instructions:
   *    EVAL expr4a             Push result of "expr4a"
!  *    JUMP_IF_COND_FALSE end
   *    EVAL expr4b             Push result of "expr4b"
!  *    JUMP_IF_COND_FALSE end
   *    EVAL expr4c             Push result of "expr4c"
+  *    COND2BOOL
   * end:
   */
      static int
***************
*** 4111,4120 ****
   *
   * Produces instructions:
   *    EVAL expr3a             Push result of "expr3a"
!  *    JUMP_AND_KEEP_IF_TRUE end
   *    EVAL expr3b             Push result of "expr3b"
!  *    JUMP_AND_KEEP_IF_TRUE end
   *    EVAL expr3c             Push result of "expr3c"
   * end:
   */
      static int
--- 4125,4135 ----
   *
   * Produces instructions:
   *    EVAL expr3a             Push result of "expr3a"
!  *    JUMP_IF_COND_TRUE end
   *    EVAL expr3b             Push result of "expr3b"
!  *    JUMP_IF_COND_TRUE end
   *    EVAL expr3c             Push result of "expr3c"
+  *    COND2BOOL
   * end:
   */
      static int
***************
*** 7415,7420 ****
--- 7430,7436 ----
        case ISN_COMPARESPECIAL:
        case ISN_COMPARESTRING:
        case ISN_CONCAT:
+       case ISN_COND2BOOL:
        case ISN_DROP:
        case ISN_ECHO:
        case ISN_ECHOERR:
*** ../vim-8.2.1794/src/vim9execute.c   2020-10-01 13:01:30.876933240 +0200
--- src/vim9execute.c   2020-10-03 22:15:03.401057661 +0200
***************
*** 1901,1914 ****
            case ISN_JUMP:
                {
                    jumpwhen_T  when = iptr->isn_arg.jump.jump_when;
                    int         jump = TRUE;
  
                    if (when != JUMP_ALWAYS)
                    {
                        tv = STACK_TV_BOT(-1);
!                       jump = tv2bool(tv);
                        if (when == JUMP_IF_FALSE
!                                            || when == JUMP_AND_KEEP_IF_FALSE)
                            jump = !jump;
                        if (when == JUMP_IF_FALSE || !jump)
                        {
--- 1901,1925 ----
            case ISN_JUMP:
                {
                    jumpwhen_T  when = iptr->isn_arg.jump.jump_when;
+                   int         error = FALSE;
                    int         jump = TRUE;
  
                    if (when != JUMP_ALWAYS)
                    {
                        tv = STACK_TV_BOT(-1);
!                       if (when == JUMP_IF_COND_FALSE
!                               || when == JUMP_IF_COND_TRUE)
!                       {
!                           SOURCING_LNUM = iptr->isn_lnum;
!                           jump = tv_get_bool_chk(tv, &error);
!                           if (error)
!                               goto on_error;
!                       }
!                       else
!                           jump = tv2bool(tv);
                        if (when == JUMP_IF_FALSE
!                                            || when == JUMP_AND_KEEP_IF_FALSE
!                                            || when == JUMP_IF_COND_FALSE)
                            jump = !jump;
                        if (when == JUMP_IF_FALSE || !jump)
                        {
***************
*** 2624,2636 ****
                break;
  
            case ISN_2BOOL:
                {
                    int n;
  
                    tv = STACK_TV_BOT(-1);
!                   n = tv2bool(tv);
!                   if (iptr->isn_arg.number)  // invert
!                       n = !n;
                    clear_tv(tv);
                    tv->v_type = VAR_BOOL;
                    tv->vval.v_number = n ? VVAL_TRUE : VVAL_FALSE;
--- 2635,2659 ----
                break;
  
            case ISN_2BOOL:
+           case ISN_COND2BOOL:
                {
                    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)
!                           goto on_error;
!                   }
                    clear_tv(tv);
                    tv->v_type = VAR_BOOL;
                    tv->vval.v_number = n ? VVAL_TRUE : VVAL_FALSE;
***************
*** 3192,3197 ****
--- 3215,3226 ----
                        case JUMP_AND_KEEP_IF_FALSE:
                            when = "JUMP_AND_KEEP_IF_FALSE";
                            break;
+                       case JUMP_IF_COND_FALSE:
+                           when = "JUMP_IF_COND_FALSE";
+                           break;
+                       case JUMP_IF_COND_TRUE:
+                           when = "JUMP_IF_COND_TRUE";
+                           break;
                    }
                    smsg("%4d %s -> %d", current, when,
                                                iptr->isn_arg.jump.jump_where);
***************
*** 3342,3347 ****
--- 3371,3377 ----
                                iptr->isn_arg.checklen.cl_more_OK ? ">= " : "",
                                iptr->isn_arg.checklen.cl_min_len);
                               break;
+           case ISN_COND2BOOL: smsg("%4d COND2BOOL", current); break;
            case ISN_2BOOL: if (iptr->isn_arg.number)
                                smsg("%4d INVERT (!val)", current);
                            else
*** ../vim-8.2.1794/src/vim9type.c      2020-10-03 20:16:48.775216665 +0200
--- src/vim9type.c      2020-10-03 20:50:29.073621598 +0200
***************
*** 360,372 ****
  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 *
--- 360,371 ----
  need_convert_to_bool(type_T *type, typval_T *tv)
  {
      return type != NULL && type == &t_bool && tv->v_type != VAR_BOOL
!           && (tv->v_type == VAR_NUMBER
!                      && (tv->vval.v_number == 0 || tv->vval.v_number == 1));
  }
  
  /*
!  * Get a type_T for a typval_T.
   * "type_list" is used to temporarily create types in.
   */
      type_T *
***************
*** 375,383 ****
      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 = get_type_ptr(type_gap);
  
--- 374,381 ----
      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)))
      {
        type_T *newtype = get_type_ptr(type_gap);
  
*** ../vim-8.2.1794/src/structs.h       2020-09-16 15:41:06.470287510 +0200
--- src/structs.h       2020-10-03 20:49:29.513787627 +0200
***************
*** 1382,1388 ****
  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
--- 1382,1388 ----
  typedef struct
  {
      vartype_T v_type;
!     char      v_lock;     // see below: VAR_LOCKED, VAR_FIXED
      union
      {
        varnumber_T     v_number;       // number value
***************
*** 1409,1415 ****
  // 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.
--- 1409,1414 ----
*** ../vim-8.2.1794/src/vim9.h  2020-10-01 13:01:30.876933240 +0200
--- src/vim9.h  2020-10-03 21:43:27.946855130 +0200
***************
*** 128,134 ****
      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,            // convert value to bool, invert if isn_arg.number 
!= 0
      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
--- 128,135 ----
      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
***************
*** 171,178 ****
  typedef enum {
      JUMP_ALWAYS,
      JUMP_IF_FALSE,            // pop and jump if false
!     JUMP_AND_KEEP_IF_TRUE,    // jump if top of stack is true, drop if not
!     JUMP_AND_KEEP_IF_FALSE,   // jump if top of stack is false, drop if not
  } jumpwhen_T;
  
  // arguments to ISN_JUMP
--- 172,181 ----
  typedef enum {
      JUMP_ALWAYS,
      JUMP_IF_FALSE,            // pop and jump if false
!     JUMP_AND_KEEP_IF_TRUE,    // jump if top of stack is truthy, drop if not
!     JUMP_AND_KEEP_IF_FALSE,   // jump if top of stack is falsy, drop if not
!     JUMP_IF_COND_TRUE,                // jump if top of stack is true, drop 
if not
!     JUMP_IF_COND_FALSE,               // jump if top of stack is false, drop 
if not
  } jumpwhen_T;
  
  // arguments to ISN_JUMP
*** ../vim-8.2.1794/src/testdir/test_vim9_expr.vim      2020-10-03 
20:16:48.775216665 +0200
--- src/testdir/test_vim9_expr.vim      2020-10-03 22:27:15.835065220 +0200
***************
*** 196,227 ****
  
  " test ||
  def Test_expr2()
!   assert_equal(2, 2 || 0)
!   assert_equal(7, 0 ||
                    0 ||
!                   7)
!   assert_equal(0, 0 || 0)
!   assert_equal(0, 0
                    || 0)
!   assert_equal('', 0 || '')
  
    g:vals = []
!   assert_equal(3, Record(3) || Record(1))
!   assert_equal([3], g:vals)
  
    g:vals = []
!   assert_equal(5, Record(0) || Record(5))
!   assert_equal([0, 5], g:vals)
  
    g:vals = []
!   assert_equal(4, Record(0)
!                     || Record(4)
                      || Record(0))
!   assert_equal([0, 4], g:vals)
  
    g:vals = []
!   assert_equal(0, Record([]) || Record('') || Record(0))
!   assert_equal([[], '', 0], g:vals)
  enddef
  
  def Test_expr2_vimscript()
--- 196,227 ----
  
  " test ||
  def Test_expr2()
!   assert_equal(true, 1 || 0)
!   assert_equal(true, 0 ||
                    0 ||
!                   1)
!   assert_equal(false, 0 || 0)
!   assert_equal(false, 0
                    || 0)
!   assert_equal(false, 0 || false)
  
    g:vals = []
!   assert_equal(true, Record(1) || Record(3))
!   assert_equal([1], g:vals)
  
    g:vals = []
!   assert_equal(true, Record(0) || Record(1))
!   assert_equal([0, 1], g:vals)
  
    g:vals = []
!   assert_equal(true, Record(0)
!                     || Record(1)
                      || Record(0))
!   assert_equal([0, 1], g:vals)
  
    g:vals = []
!   assert_equal(false, Record(0) || Record(false) || Record(0))
!   assert_equal([0, false, 0], g:vals)
  enddef
  
  def Test_expr2_vimscript()
***************
*** 230,236 ****
        vim9script
        var name = 0
                        || 1
!       assert_equal(1, name)
    END
    CheckScriptSuccess(lines)
  
--- 230,236 ----
        vim9script
        var name = 0
                        || 1
!       assert_equal(true, name)
    END
    CheckScriptSuccess(lines)
  
***************
*** 269,348 ****
    END
    CheckScriptFailure(lines, 'E1004:', 2)
  
!   # check keeping the value
    lines =<< trim END
!       vim9script
!       assert_equal(2, 2 || 0)
!       assert_equal(7, 0 ||
                        0 ||
!                       7)
!       assert_equal(0, 0 || 0)
!       assert_equal(0, 0
                        || 0)
!       assert_equal('', 0 || '')
  
        g:vals = []
!       assert_equal(3, Record(3) || Record(1))
!       assert_equal([3], g:vals)
  
        g:vals = []
!       assert_equal(5, Record(0) || Record(5))
!       assert_equal([0, 5], g:vals)
  
        g:vals = []
!       assert_equal(4, Record(0)
!                         || Record(4)
                          || Record(0))
!       assert_equal([0, 4], g:vals)
  
        g:vals = []
!       assert_equal(0, Record([]) || Record('') || Record(0))
!       assert_equal([[], '', 0], g:vals)
    END
!   CheckScriptSuccess(lines)
  enddef
  
! func Test_expr2_fails()
!   let msg = "White space required before and after '||'"
    call CheckDefFailure(["var x = 1||2"], msg, 1)
    call CheckDefFailure(["var x = 1 ||2"], msg, 1)
    call CheckDefFailure(["var x = 1|| 2"], msg, 1)
  
    call CheckDefFailure(["var x = 1 || xxx"], 'E1001:', 1)
! endfunc
  
  " test &&
  def Test_expr3()
!   assert_equal(0, 2 && 0)
!   assert_equal(0, 0 &&
                0 &&
!               7)
!   assert_equal(7, 2
!                   && 3
!                   && 7)
!   assert_equal(0, 0 && 0)
!   assert_equal(0, 0 && '')
!   assert_equal('', 8 && '')
  
    g:vals = []
!   assert_equal(1, Record(3) && Record(1))
!   assert_equal([3, 1], g:vals)
  
    g:vals = []
!   assert_equal(0, Record(0) && Record(5))
    assert_equal([0], g:vals)
  
    g:vals = []
!   assert_equal(0, Record(0) && Record(4) && Record(0))
    assert_equal([0], g:vals)
  
    g:vals = []
!   assert_equal(0, Record(8) && Record(4) && Record(0))
!   assert_equal([8, 4, 0], g:vals)
  
    g:vals = []
!   assert_equal(0, Record([1]) && Record('z') && Record(0))
!   assert_equal([[1], 'z', 0], g:vals)
  enddef
  
  def Test_expr3_vimscript()
--- 269,353 ----
    END
    CheckScriptFailure(lines, 'E1004:', 2)
  
!   # check evaluating to bool
    lines =<< trim END
!       assert_equal(true, 1 || 0)
!       assert_equal(true, 0 ||
                        0 ||
!                       !!7)
!       assert_equal(false, 0 || 0)
!       assert_equal(false, 0
                        || 0)
!       assert_equal(false, 0 || false)
  
        g:vals = []
!       assert_equal(true, Record(true) || Record(false))
!       assert_equal([true], g:vals)
  
        g:vals = []
!       assert_equal(true, Record(0) || Record(true))
!       assert_equal([0, true], g:vals)
  
        g:vals = []
!       assert_equal(true, Record(0)
!                         || Record(true)
                          || Record(0))
!       assert_equal([0, true], g:vals)
  
        g:vals = []
!       assert_equal(false, Record(0) || Record(false) || Record(0))
!       assert_equal([0, false, 0], g:vals)
    END
!   CheckDefAndScriptSuccess(lines)
  enddef
  
! def Test_expr2_fails()
!   var msg = "White space required before and after '||'"
    call CheckDefFailure(["var x = 1||2"], msg, 1)
    call CheckDefFailure(["var x = 1 ||2"], msg, 1)
    call CheckDefFailure(["var x = 1|| 2"], msg, 1)
  
    call CheckDefFailure(["var x = 1 || xxx"], 'E1001:', 1)
! 
!   # TODO: should fail at compile time
!   call CheckDefExecFailure(["var x = 3 || 7"], 'E1023:', 1)
!   call CheckScriptFailure(["vim9script", "var x = 3 || 7"], 'E1023:', 2)
!   call CheckDefExecFailure(["var x = [] || false"], 'E745:', 1)
!   call CheckScriptFailure(["vim9script", "var x = [] || false"], 'E745:', 2)
! enddef
  
  " test &&
  def Test_expr3()
!   assert_equal(false, 1 && 0)
!   assert_equal(false, 0 &&
                0 &&
!               1)
!   assert_equal(true, 1
!                   && true
!                   && 1)
!   assert_equal(false, 0 && 0)
!   assert_equal(false, 0 && false)
!   assert_equal(true, 1 && true)
  
    g:vals = []
!   assert_equal(true, Record(true) && Record(1))
!   assert_equal([true, 1], g:vals)
  
    g:vals = []
!   assert_equal(false, Record(0) && Record(1))
    assert_equal([0], g:vals)
  
    g:vals = []
!   assert_equal(false, Record(0) && Record(4) && Record(0))
    assert_equal([0], g:vals)
  
    g:vals = []
!   assert_equal(false, Record(1) && Record(true) && Record(0))
!   assert_equal([1, true, 0], g:vals)
  
    g:vals = []
!   assert_equal(false, Record(1) && Record(true) && Record(0))
!   assert_equal([1, true, 0], g:vals)
  enddef
  
  def Test_expr3_vimscript()
***************
*** 351,357 ****
        vim9script
        var name = 0
                        && 1
!       assert_equal(0, name)
    END
    CheckScriptSuccess(lines)
  
--- 356,362 ----
        vim9script
        var name = 0
                        && 1
!       assert_equal(false, name)
    END
    CheckScriptSuccess(lines)
  
***************
*** 393,428 ****
    # check keeping the value
    lines =<< trim END
        vim9script
!       assert_equal(0, 2 && 0)
!       assert_equal(0, 0 &&
                    0 &&
!                   7)
!       assert_equal(7, 2
!                       && 3
!                       && 7)
!       assert_equal(0, 0 && 0)
!       assert_equal(0, 0 && '')
!       assert_equal('', 8 && '')
  
        g:vals = []
!       assert_equal(1, Record(3) && Record(1))
!       assert_equal([3, 1], g:vals)
  
        g:vals = []
!       assert_equal(0, Record(0) && Record(5))
        assert_equal([0], g:vals)
  
        g:vals = []
!       assert_equal(0, Record(0) && Record(4) && Record(0))
        assert_equal([0], g:vals)
  
        g:vals = []
!       assert_equal(0, Record(8) && Record(4) && Record(0))
!       assert_equal([8, 4, 0], g:vals)
! 
!       g:vals = []
!       assert_equal(0, Record([1]) && Record('z') && Record(0))
!       assert_equal([[1], 'z', 0], g:vals)
    END
    CheckScriptSuccess(lines)
  enddef
--- 398,429 ----
    # check keeping the value
    lines =<< trim END
        vim9script
!       assert_equal(false, 1 && 0)
!       assert_equal(false, 0 &&
                    0 &&
!                   1)
!       assert_equal(true, 1
!                       && true
!                       && 1)
!       assert_equal(false, 0 && 0)
!       assert_equal(false, 0 && false)
!       assert_equal(false, 1 && 0)
  
        g:vals = []
!       assert_equal(true, Record(1) && Record(true))
!       assert_equal([1, true], g:vals)
  
        g:vals = []
!       assert_equal(false, Record(0) && Record(1))
        assert_equal([0], g:vals)
  
        g:vals = []
!       assert_equal(false, Record(0) && Record(1) && Record(0))
        assert_equal([0], g:vals)
  
        g:vals = []
!       assert_equal(false, Record(1) && Record(true) && Record(0))
!       assert_equal([1, true, 0], g:vals)
    END
    CheckScriptSuccess(lines)
  enddef
*** ../vim-8.2.1794/src/testdir/test_vim9_assign.vim    2020-09-30 
22:59:37.904243979 +0200
--- src/testdir/test_vim9_assign.vim    2020-10-03 22:33:52.265895466 +0200
***************
*** 22,32 ****
    var bool4: bool = 1
    assert_equal(true, bool4)
  
!   var bool5: bool = 'yes' && 'no'
    assert_equal(true, bool5)
!   var bool6: bool = [] && 99
    assert_equal(false, bool6)
!   var bool7: bool = [] || #{a: 1} && 99
    assert_equal(true, bool7)
  
    var lines =<< trim END
--- 22,32 ----
    var bool4: bool = 1
    assert_equal(true, bool4)
  
!   var bool5: bool = 1 && true
    assert_equal(true, bool5)
!   var bool6: bool = 0 && 1
    assert_equal(false, bool6)
!   var bool7: bool = 0 || 1 && true
    assert_equal(true, bool7)
  
    var lines =<< trim END
***************
*** 41,49 ****
      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)
--- 41,49 ----
      assert_equal(false, flag)
      flag = 1
      assert_equal(true, flag)
!     flag = 1 || true
      assert_equal(true, flag)
!     flag = 1 && false
      assert_equal(false, flag)
    END
    CheckScriptSuccess(lines)
*** ../vim-8.2.1794/src/testdir/test_vim9_cmd.vim       2020-09-27 
22:47:01.880163387 +0200
--- src/testdir/test_vim9_cmd.vim       2020-10-03 22:34:44.521739226 +0200
***************
*** 72,79 ****
    var lines =<< trim END
        vim9script
        if 1 &&
!             2
!             || 3
          g:res = 42
        endif
        assert_equal(42, g:res)
--- 72,79 ----
    var lines =<< trim END
        vim9script
        if 1 &&
!             true
!             || 1
          g:res = 42
        endif
        assert_equal(42, g:res)
*** ../vim-8.2.1794/src/testdir/test_vim9_disassemble.vim       2020-10-03 
20:16:48.775216665 +0200
--- src/testdir/test_vim9_disassemble.vim       2020-10-03 22:41:11.484573913 
+0200
***************
*** 766,776 ****
          '\d LOAD arg\[-1]\_s*' ..
          '\d PUSHNR 1\_s*' ..
          '\d COMPAREANY ==\_s*' ..
!         '\d JUMP_AND_KEEP_IF_FALSE -> \d\+\_s*' ..
          '\d LOAD arg\[-1]\_s*' ..
          '\d PUSHNR 2\_s*' ..
          '\d COMPAREANY !=\_s*' ..
!         '\d JUMP_AND_KEEP_IF_TRUE -> \d\+\_s*' ..
          '\d LOAD arg\[-1]\_s*' ..
          '\d\+ PUSHNR 4\_s*' ..
          '\d\+ COMPAREANY ==\_s*' ..
--- 766,776 ----
          '\d LOAD arg\[-1]\_s*' ..
          '\d PUSHNR 1\_s*' ..
          '\d COMPAREANY ==\_s*' ..
!         '\d JUMP_IF_COND_FALSE -> \d\+\_s*' ..
          '\d LOAD arg\[-1]\_s*' ..
          '\d PUSHNR 2\_s*' ..
          '\d COMPAREANY !=\_s*' ..
!         '\d JUMP_IF_COND_TRUE -> \d\+\_s*' ..
          '\d LOAD arg\[-1]\_s*' ..
          '\d\+ PUSHNR 4\_s*' ..
          '\d\+ COMPAREANY ==\_s*' ..
***************
*** 1200,1221 ****
  enddef
  
  def ReturnBool(): bool
!   var var: bool = "no" && [] || 123
!   return var
  enddef
  
  def Test_disassemble_return_bool()
    var instr = execute('disassemble ReturnBool')
    assert_match('ReturnBool\_s*' ..
!         'var var: bool = "no" && \[\] || 123\_s*' ..
!         '0 PUSHS "no"\_s*' ..
!         '1 JUMP_AND_KEEP_IF_FALSE -> 3\_s*' ..
!         '2 NEWLIST size 0\_s*' ..
!         '3 JUMP_AND_KEEP_IF_TRUE -> 5\_s*' ..
!         '4 PUSHNR 123\_s*' ..
!         '5 2BOOL (!!val)\_s*' ..
          '\d STORE $0\_s*' ..
!         'return var\_s*' ..
          '\d LOAD $0\_s*' ..   
          '\d RETURN',
          instr)
--- 1200,1222 ----
  enddef
  
  def ReturnBool(): bool
!   var name: bool = 1 && 0 || 1
!   return name
  enddef
  
  def Test_disassemble_return_bool()
    var instr = execute('disassemble ReturnBool')
    assert_match('ReturnBool\_s*' ..
!         'var name: bool = 1 && 0 || 1\_s*' ..
!         '0 PUSHNR 1\_s*' ..
!         '1 JUMP_IF_COND_FALSE -> 3\_s*' ..
!         '2 PUSHNR 0\_s*' ..
!         '3 COND2BOOL\_s*' ..
!         '4 JUMP_IF_COND_TRUE -> 6\_s*' ..
!         '5 PUSHNR 1\_s*' ..
!         '6 2BOOL (!!val)\_s*' ..
          '\d STORE $0\_s*' ..
!         'return name\_s*' ..
          '\d LOAD $0\_s*' ..   
          '\d RETURN',
          instr)
*** ../vim-8.2.1794/src/version.c       2020-10-03 20:16:48.775216665 +0200
--- src/version.c       2020-10-03 22:45:42.051753334 +0200
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     1795,
  /**/

-- 
"Space is big.  Really big.  You just won't believe how vastly hugely mind-
bogglingly big it is.  I mean, you may think it's a long way down the
road to the chemist, but that's just peanuts to space."
                -- Douglas Adams, "The Hitchhiker's Guide to the Galaxy"

 /// 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/202010032053.093Kr9091937337%40masaka.moolenaar.net.

Raspunde prin e-mail lui