Patch 8.2.4539
Problem:    When comparing special v:none and v:null are handled the same when
            compiling.
Solution:   Pass more information so that v:none can be handled differently at
            compile time.  (issue #9923)
Files:      src/vim9instr.c, src/vim9compile.c, src/globals.h,
            src/testdir/test_vim9_expr.vim


*** ../vim-8.2.4538/src/vim9instr.c     2022-03-08 19:43:51.688198945 +0000
--- src/vim9instr.c     2022-03-10 19:12:38.710964636 +0000
***************
*** 339,360 ****
  }
  
  /*
!  * Get the instruction to use for comparing "type1" with "type2"
   * Return ISN_DROP when failed.
   */
      static isntype_T
! get_compare_isn(exprtype_T exprtype, vartype_T type1, vartype_T type2)
  {
      isntype_T isntype = ISN_DROP;
  
!     if (type1 == VAR_UNKNOWN)
!       type1 = VAR_ANY;
!     if (type2 == VAR_UNKNOWN)
!       type2 = VAR_ANY;
  
!     if (type1 == type2)
      {
!       switch (type1)
        {
            case VAR_BOOL: isntype = ISN_COMPAREBOOL; break;
            case VAR_SPECIAL: isntype = ISN_COMPARESPECIAL; break;
--- 339,368 ----
  }
  
  /*
!  * Get the instruction to use for comparing two values with specified types.
!  * Either "tv1" and "tv2" are passed or "type1" and "type2".
   * Return ISN_DROP when failed.
   */
      static isntype_T
! get_compare_isn(
!       exprtype_T exprtype,
!       typval_T    *tv1,
!       typval_T    *tv2,
!       type_T      *type1,
!       type_T      *type2)
  {
      isntype_T isntype = ISN_DROP;
+     vartype_T vartype1 = tv1 != NULL ? tv1->v_type : type1->tt_type;
+     vartype_T vartype2 = tv2 != NULL ? tv2->v_type : type2->tt_type;
  
!     if (vartype1 == VAR_UNKNOWN)
!       vartype1 = VAR_ANY;
!     if (vartype2 == VAR_UNKNOWN)
!       vartype2 = VAR_ANY;
  
!     if (vartype1 == vartype2)
      {
!       switch (vartype1)
        {
            case VAR_BOOL: isntype = ISN_COMPAREBOOL; break;
            case VAR_SPECIAL: isntype = ISN_COMPARESPECIAL; break;
***************
*** 368,382 ****
            default: isntype = ISN_COMPAREANY; break;
        }
      }
!     else if (type1 == VAR_ANY || type2 == VAR_ANY
!           || ((type1 == VAR_NUMBER || type1 == VAR_FLOAT)
!                              && (type2 == VAR_NUMBER || type2 == VAR_FLOAT))
!           || (type1 == VAR_FUNC && type2 == VAR_PARTIAL)
!           || (type1 == VAR_PARTIAL && type2 == VAR_FUNC))
        isntype = ISN_COMPAREANY;
!     else if (type1 == VAR_SPECIAL || type2 == VAR_SPECIAL)
      {
!       switch (type1 == VAR_SPECIAL ? type2 : type1)
        {
            case VAR_BLOB: break;
            case VAR_CHANNEL: break;
--- 376,403 ----
            default: isntype = ISN_COMPAREANY; break;
        }
      }
!     else if (vartype1 == VAR_ANY || vartype2 == VAR_ANY
!           || ((vartype1 == VAR_NUMBER || vartype1 == VAR_FLOAT)
!                         && (vartype2 == VAR_NUMBER || vartype2 == VAR_FLOAT))
!           || (vartype1 == VAR_FUNC && vartype2 == VAR_PARTIAL)
!           || (vartype1 == VAR_PARTIAL && vartype2 == VAR_FUNC))
        isntype = ISN_COMPAREANY;
!     else if (vartype1 == VAR_SPECIAL || vartype2 == VAR_SPECIAL)
      {
!       if ((vartype1 == VAR_SPECIAL
!               && (tv1 != NULL ? tv1->vval.v_number == VVAL_NONE
!                                                           : type1 == &t_none)
!               && vartype2 != VAR_STRING)
!           || (vartype2 == VAR_SPECIAL
!               && (tv2 != NULL ? tv2->vval.v_number == VVAL_NONE
!                                                           : type2 == &t_none)
!               && vartype1 != VAR_STRING))
!       {
!           semsg(_(e_cannot_compare_str_with_str),
!                              vartype_name(vartype1), vartype_name(vartype2));
!           return ISN_DROP;
!       }
!       switch (vartype1 == VAR_SPECIAL ? vartype2 : vartype1)
        {
            case VAR_BLOB: break;
            case VAR_CHANNEL: break;
***************
*** 387,393 ****
            case VAR_PARTIAL: break;
            case VAR_STRING: break;
            default: semsg(_(e_cannot_compare_str_with_str),
!                                  vartype_name(type1), vartype_name(type2));
                     return ISN_DROP;
        }
        isntype = ISN_COMPARENULL;
--- 408,414 ----
            case VAR_PARTIAL: break;
            case VAR_STRING: break;
            default: semsg(_(e_cannot_compare_str_with_str),
!                              vartype_name(vartype1), vartype_name(vartype2));
                     return ISN_DROP;
        }
        isntype = ISN_COMPARENULL;
***************
*** 400,419 ****
            || isntype == ISN_COMPAREFLOAT))
      {
        semsg(_(e_cannot_use_str_with_str),
!               exprtype == EXPR_IS ? "is" : "isnot" , vartype_name(type1));
        return ISN_DROP;
      }
      if (isntype == ISN_DROP
            || ((exprtype != EXPR_EQUAL && exprtype != EXPR_NEQUAL
!                   && (type1 == VAR_BOOL || type1 == VAR_SPECIAL
!                      || type2 == VAR_BOOL || type2 == VAR_SPECIAL)))
            || ((exprtype != EXPR_EQUAL && exprtype != EXPR_NEQUAL
                               && exprtype != EXPR_IS && exprtype != EXPR_ISNOT
!                   && (type1 == VAR_BLOB || type2 == VAR_BLOB
!                       || type1 == VAR_LIST || type2 == VAR_LIST))))
      {
        semsg(_(e_cannot_compare_str_with_str),
!               vartype_name(type1), vartype_name(type2));
        return ISN_DROP;
      }
      return isntype;
--- 421,440 ----
            || isntype == ISN_COMPAREFLOAT))
      {
        semsg(_(e_cannot_use_str_with_str),
!               exprtype == EXPR_IS ? "is" : "isnot" , vartype_name(vartype1));
        return ISN_DROP;
      }
      if (isntype == ISN_DROP
            || ((exprtype != EXPR_EQUAL && exprtype != EXPR_NEQUAL
!                   && (vartype1 == VAR_BOOL || vartype1 == VAR_SPECIAL
!                      || vartype2 == VAR_BOOL || vartype2 == VAR_SPECIAL)))
            || ((exprtype != EXPR_EQUAL && exprtype != EXPR_NEQUAL
                               && exprtype != EXPR_IS && exprtype != EXPR_ISNOT
!                   && (vartype1 == VAR_BLOB || vartype2 == VAR_BLOB
!                       || vartype1 == VAR_LIST || vartype2 == VAR_LIST))))
      {
        semsg(_(e_cannot_compare_str_with_str),
!               vartype_name(vartype1), vartype_name(vartype2));
        return ISN_DROP;
      }
      return isntype;
***************
*** 422,428 ****
      int
  check_compare_types(exprtype_T type, typval_T *tv1, typval_T *tv2)
  {
!     if (get_compare_isn(type, tv1->v_type, tv2->v_type) == ISN_DROP)
        return FAIL;
      return OK;
  }
--- 443,449 ----
      int
  check_compare_types(exprtype_T type, typval_T *tv1, typval_T *tv2)
  {
!     if (get_compare_isn(type, tv1, tv2, NULL, NULL) == ISN_DROP)
        return FAIL;
      return OK;
  }
***************
*** 436,452 ****
      isntype_T isntype;
      isn_T     *isn;
      garray_T  *stack = &cctx->ctx_type_stack;
-     vartype_T type1;
-     vartype_T type2;
  
      RETURN_OK_IF_SKIP(cctx);
  
      // Get the known type of the two items on the stack.  If they are matching
      // use a type-specific instruction. Otherwise fall back to runtime type
      // checking.
!     type1 = get_type_on_stack(cctx, 1)->tt_type;
!     type2 = get_type_on_stack(cctx, 0)->tt_type;
!     isntype = get_compare_isn(exprtype, type1, type2);
      if (isntype == ISN_DROP)
        return FAIL;
  
--- 457,470 ----
      isntype_T isntype;
      isn_T     *isn;
      garray_T  *stack = &cctx->ctx_type_stack;
  
      RETURN_OK_IF_SKIP(cctx);
  
      // Get the known type of the two items on the stack.  If they are matching
      // use a type-specific instruction. Otherwise fall back to runtime type
      // checking.
!     isntype = get_compare_isn(exprtype, NULL, NULL,
!                      get_type_on_stack(cctx, 1), get_type_on_stack(cctx, 0));
      if (isntype == ISN_DROP)
        return FAIL;
  
***************
*** 664,670 ****
      isn_T     *isn;
  
      RETURN_OK_IF_SKIP(cctx);
!     if ((isn = generate_instr_type(cctx, ISN_PUSHSPEC, &t_special)) == NULL)
        return FAIL;
      isn->isn_arg.number = number;
  
--- 682,689 ----
      isn_T     *isn;
  
      RETURN_OK_IF_SKIP(cctx);
!     if ((isn = generate_instr_type(cctx, ISN_PUSHSPEC,
!                            number == VVAL_NULL ? &t_null : &t_none)) == NULL)
        return FAIL;
      isn->isn_arg.number = number;
  
***************
*** 1475,1481 ****
            type_T *actual;
  
            actual = get_type_on_stack(cctx, argcount - i - 1);
!           if (actual == &t_special
                              && i >= regular_args - ufunc->uf_def_args.ga_len)
            {
                // assume v:none used for default argument value
--- 1494,1500 ----
            type_T *actual;
  
            actual = get_type_on_stack(cctx, argcount - i - 1);
!           if (actual->tt_type == VAR_SPECIAL
                              && i >= regular_args - ufunc->uf_def_args.ga_len)
            {
                // assume v:none used for default argument value
***************
*** 1606,1612 ****
                        expected = type->tt_args[
                                             type->tt_argcount - 1]->tt_member;
                    else if (i >= type->tt_min_argcount
!                                                      && actual == &t_special)
                        expected = &t_any;
                    else
                        expected = type->tt_args[i];
--- 1625,1631 ----
                        expected = type->tt_args[
                                             type->tt_argcount - 1]->tt_member;
                    else if (i >= type->tt_min_argcount
!                                            && actual->tt_type == VAR_SPECIAL)
                        expected = &t_any;
                    else
                        expected = type->tt_args[i];
*** ../vim-8.2.4538/src/vim9compile.c   2022-03-08 13:18:10.809020782 +0000
--- src/vim9compile.c   2022-03-10 19:06:02.375695990 +0000
***************
*** 1799,1805 ****
                return FAIL;
            }
            type = get_type_on_stack(cctx, 0);
!           if ((dest_type != VAR_BLOB && type != &t_special)
                    && need_type(type, &t_number,
                                            -1, 0, cctx, FALSE, FALSE) == FAIL)
                return FAIL;
--- 1799,1805 ----
                return FAIL;
            }
            type = get_type_on_stack(cctx, 0);
!           if ((dest_type != VAR_BLOB && type->tt_type != VAR_SPECIAL)
                    && need_type(type, &t_number,
                                            -1, 0, cctx, FALSE, FALSE) == FAIL)
                return FAIL;
*** ../vim-8.2.4538/src/globals.h       2022-02-11 20:33:11.942342190 +0000
--- src/globals.h       2022-03-10 19:06:20.151664158 +0000
***************
*** 398,404 ****
  EXTERN type_T t_void INIT6(VAR_VOID, 0, 0, TTFLAG_STATIC, NULL, NULL);
  
  EXTERN type_T t_bool INIT6(VAR_BOOL, 0, 0, TTFLAG_STATIC, NULL, NULL);
! EXTERN type_T t_special INIT6(VAR_SPECIAL, 0, 0, TTFLAG_STATIC, NULL, NULL);
  EXTERN type_T t_number INIT6(VAR_NUMBER, 0, 0, TTFLAG_STATIC, NULL, NULL);
  EXTERN type_T t_number_bool INIT6(VAR_NUMBER, 0, 0, 
TTFLAG_STATIC|TTFLAG_BOOL_OK, NULL, NULL);
  EXTERN type_T t_float INIT6(VAR_FLOAT, 0, 0, TTFLAG_STATIC, NULL, NULL);
--- 398,405 ----
  EXTERN type_T t_void INIT6(VAR_VOID, 0, 0, TTFLAG_STATIC, NULL, NULL);
  
  EXTERN type_T t_bool INIT6(VAR_BOOL, 0, 0, TTFLAG_STATIC, NULL, NULL);
! EXTERN type_T t_null INIT6(VAR_SPECIAL, 0, 0, TTFLAG_STATIC, NULL, NULL);
! EXTERN type_T t_none INIT6(VAR_SPECIAL, 0, 0, TTFLAG_STATIC, NULL, NULL);
  EXTERN type_T t_number INIT6(VAR_NUMBER, 0, 0, TTFLAG_STATIC, NULL, NULL);
  EXTERN type_T t_number_bool INIT6(VAR_NUMBER, 0, 0, 
TTFLAG_STATIC|TTFLAG_BOOL_OK, NULL, NULL);
  EXTERN type_T t_float INIT6(VAR_FLOAT, 0, 0, TTFLAG_STATIC, NULL, NULL);
*** ../vim-8.2.4538/src/testdir/test_vim9_expr.vim      2022-03-10 
12:20:48.542552970 +0000
--- src/testdir/test_vim9_expr.vim      2022-03-10 19:21:06.485989124 +0000
***************
*** 828,835 ****
    v9.CheckDefAndScriptFailure(['echo true != v:null'], 'E1072: Cannot compare 
bool with special')
    v9.CheckDefAndScriptFailure(['echo v:null != true'], 'E1072: Cannot compare 
special with bool')
    v9.CheckDefAndScriptFailure(['echo false == v:null'], 'E1072: Cannot 
compare bool with special')
  
!   v9.CheckDefExecAndScriptFailure(['echo [] == v:none'], ['E1072: Cannot 
compare list with special', 'E691: Can only compare List with List'])
  enddef
  
  def Test_expr4_wrong_type()
--- 828,849 ----
    v9.CheckDefAndScriptFailure(['echo true != v:null'], 'E1072: Cannot compare 
bool with special')
    v9.CheckDefAndScriptFailure(['echo v:null != true'], 'E1072: Cannot compare 
special with bool')
    v9.CheckDefAndScriptFailure(['echo false == v:null'], 'E1072: Cannot 
compare bool with special')
+ enddef
+ 
+ def Test_expr4_compare_none()
+   var lines =<< trim END
+       assert_false('' == v:none)
+       assert_false('text' == v:none)
+       assert_true(v:none == v:none)
+       assert_false(v:none == '')
+       assert_false(v:none == 'text')
+       assert_true(v:none == v:none)
+   END
+   v9.CheckDefAndScriptSuccess(lines)
  
!   v9.CheckDefAndScriptFailure(['echo [] == v:none'], 'E1072: Cannot compare 
list with special')
!   v9.CheckDefAndScriptFailure(['echo 123 == v:none'], 'E1072: Cannot compare 
number with special')
!   v9.CheckDefAndScriptFailure(['echo 0z00 == v:none'], 'E1072: Cannot compare 
blob with special')
  enddef
  
  def Test_expr4_wrong_type()
*** ../vim-8.2.4538/src/version.c       2022-03-10 18:36:50.874611102 +0000
--- src/version.c       2022-03-10 19:21:40.625922704 +0000
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     4539,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
225. You sign up for free subscriptions for all the computer magazines

 /// 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/20220310192408.C63341C0DCA%40moolenaar.net.

Raspunde prin e-mail lui