Patch 8.2.1272
Problem:    Vim9: type not checked if declaration also assigns value.
Solution:   Check the type. (issue #6507)
Files:      src/eval.c, src/vim9compile.c, src/proto/vim9compile.pro,
            src/vim9script.c, src/vim9execute.c,
            src/testdir/test_vim9_script.vim


*** ../vim-8.2.1271/src/eval.c  2020-07-21 21:30:55.011536496 +0200
--- src/eval.c  2020-07-22 21:40:33.498575556 +0200
***************
*** 1270,1276 ****
--- 1270,1281 ----
            }
        }
        else
+       {
+           if (lp->ll_type != NULL
+                             && check_typval_type(lp->ll_type, rettv) == FAIL)
+               return;
            set_var_const(lp->ll_name, lp->ll_type, rettv, copy, flags);
+       }
        *endp = cc;
      }
      else if (var_check_lock(lp->ll_newkey == NULL
*** ../vim-8.2.1271/src/vim9compile.c   2020-07-22 20:16:08.071900823 +0200
--- src/vim9compile.c   2020-07-22 21:40:36.902564024 +0200
***************
*** 478,499 ****
  }
  
  /*
!  * Return the type_T for a typval.  Only for primitive types.
   */
      type_T *
! typval2type(typval_T *tv)
  {
      if (tv->v_type == VAR_NUMBER)
        return &t_number;
      if (tv->v_type == VAR_BOOL)
        return &t_bool;  // not used
      if (tv->v_type == VAR_STRING)
        return &t_string;
      if (tv->v_type == VAR_LIST)  // e.g. for v:oldfiles
        return &t_list_string;
      if (tv->v_type == VAR_DICT)  // e.g. for v:completed_item
        return &t_dict_any;
!     return &t_any;  // not used
  }
  
      static void
--- 478,583 ----
  }
  
  /*
!  * 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  *actual;
+     type_T  *member_type;
+ 
      if (tv->v_type == VAR_NUMBER)
        return &t_number;
      if (tv->v_type == VAR_BOOL)
        return &t_bool;  // not used
      if (tv->v_type == VAR_STRING)
        return &t_string;
+ 
+     if (tv->v_type == VAR_LIST
+           && tv->vval.v_list != NULL
+           && tv->vval.v_list->lv_first != NULL)
+     {
+       // Use the type of the first member, it is the most specific.
+       member_type = typval2type(&tv->vval.v_list->lv_first->li_tv, type_gap);
+       return get_list_type(member_type, type_gap);
+     }
+ 
+     if (tv->v_type == VAR_DICT
+           && tv->vval.v_dict != NULL
+           && tv->vval.v_dict->dv_hashtab.ht_used > 0)
+     {
+       dict_iterator_T iter;
+       typval_T        *value;
+ 
+       // Use the type of the first value, it is the most specific.
+       dict_iterate_start(tv, &iter);
+       dict_iterate_next(&iter, &value);
+       member_type = typval2type(value, type_gap);
+       return get_dict_type(member_type, type_gap);
+     }
+ 
+     if (tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL)
+     {
+       char_u  *name = NULL;
+       ufunc_T *ufunc = NULL;
+ 
+       if (tv->v_type == VAR_PARTIAL)
+       {
+           if (tv->vval.v_partial->pt_func != NULL)
+               ufunc = tv->vval.v_partial->pt_func;
+           else
+               name = tv->vval.v_partial->pt_name;
+       }
+       else
+           name = tv->vval.v_string;
+       if (name != NULL)
+           // TODO: how about a builtin function?
+           ufunc = find_func(name, FALSE, NULL);
+       if (ufunc != NULL && ufunc->uf_func_type != NULL)
+           return ufunc->uf_func_type;
+     }
+ 
+     actual = alloc_type(type_gap);
+     if (actual == NULL)
+       return NULL;
+     actual->tt_type = tv->v_type;
+     actual->tt_member = &t_any;
+ 
+     return actual;
+ }
+ 
+ /*
+  * Get a type_T for a typval_T, used for v: variables.
+  * "type_list" is used to temporarily create types in.
+  */
+     type_T *
+ typval2type_vimvar(typval_T *tv, garray_T *type_gap)
+ {
      if (tv->v_type == VAR_LIST)  // e.g. for v:oldfiles
        return &t_list_string;
      if (tv->v_type == VAR_DICT)  // e.g. for v:completed_item
        return &t_dict_any;
!     return typval2type(tv, type_gap);
! }
! 
! 
! /*
!  * Return FAIL if "expected" and "actual" don't match.
!  */
!     int
! check_typval_type(type_T *expected, typval_T *actual_tv)
! {
!     garray_T  type_list;
!     type_T    *actual_type;
!     int               res = FAIL;
! 
!     ga_init2(&type_list, sizeof(type_T *), 10);
!     actual_type = typval2type(actual_tv, &type_list);
!     if (actual_type != NULL)
!       res = check_type(expected, actual_type, TRUE);
!     clear_type_list(&type_list);
!     return res;
  }
  
      static void
***************
*** 561,631 ****
      return ret;
  }
  
- /*
-  * Return FAIl if "expected" and "actual" don't match.
-  * TODO: better type comparison
-  */
-     int
- check_argtype(type_T *expected, typval_T *actual_tv)
- {
-     type_T  actual;
-     type_T  member;
- 
-     // TODO: should should be done with more levels
-     CLEAR_FIELD(actual);
-     actual.tt_type = actual_tv->v_type;
-     if (actual_tv->v_type == VAR_LIST
-           && actual_tv->vval.v_list != NULL
-           && actual_tv->vval.v_list->lv_first != NULL)
-     {
-       // Use the type of the first member, it is the most specific.
-       CLEAR_FIELD(member);
-       member.tt_type = actual_tv->vval.v_list->lv_first->li_tv.v_type;
-       member.tt_member = &t_any;
-       actual.tt_member = &member;
-     }
-     else if (actual_tv->v_type == VAR_DICT
-           && actual_tv->vval.v_dict != NULL
-           && actual_tv->vval.v_dict->dv_hashtab.ht_used > 0)
-     {
-       dict_iterator_T iter;
-       typval_T        *value;
- 
-       // Use the type of the first value, it is the most specific.
-       dict_iterate_start(actual_tv, &iter);
-       dict_iterate_next(&iter, &value);
-       CLEAR_FIELD(member);
-       member.tt_type = value->v_type;
-       member.tt_member = &t_any;
-       actual.tt_member = &member;
-     }
-     else if (actual_tv->v_type == VAR_FUNC || actual_tv->v_type == 
VAR_PARTIAL)
-     {
-       char_u  *name = NULL;
-       ufunc_T *ufunc = NULL;
- 
-       if (actual_tv->v_type == VAR_PARTIAL)
-       {
-           if (actual_tv->vval.v_partial->pt_func != NULL)
-               ufunc = actual_tv->vval.v_partial->pt_func;
-           else
-               name = actual_tv->vval.v_partial->pt_name;
-       }
-       else
-           name = actual_tv->vval.v_string;
-       if (name != NULL)
-           // TODO: how about a builtin function?
-           ufunc = find_func(name, FALSE, NULL);
-       if (ufunc != NULL && ufunc->uf_func_type != NULL)
-           actual = *ufunc->uf_func_type;
-       else
-           actual.tt_member = &t_any;
-     }
-     else
-       actual.tt_member = &t_any;
-     return check_type(expected, &actual, TRUE);
- }
- 
  
  /////////////////////////////////////////////////////////////////////
  // Following generate_ functions expect the caller to call ga_grow().
--- 645,650 ----
***************
*** 1314,1320 ****
            semsg(_(e_var_notfound), name);
        return FAIL;
      }
!     type = typval2type(get_vim_var_tv(vidx));
  
      return generate_LOAD(cctx, ISN_LOADV, vidx, NULL, type);
  }
--- 1333,1339 ----
            semsg(_(e_var_notfound), name);
        return FAIL;
      }
!     type = typval2type_vimvar(get_vim_var_tv(vidx), cctx->ctx_type_list);
  
      return generate_LOAD(cctx, ISN_LOADV, vidx, NULL, type);
  }
***************
*** 5235,5241 ****
                    goto theend;
                dest = dest_vimvar;
                vtv = get_vim_var_tv(vimvaridx);
!               type = typval2type(vtv);
                if (is_decl)
                {
                    vim9_declare_error(name);
--- 5254,5260 ----
                    goto theend;
                dest = dest_vimvar;
                vtv = get_vim_var_tv(vimvaridx);
!               type = typval2type_vimvar(vtv, cctx->ctx_type_list);
                if (is_decl)
                {
                    vim9_declare_error(name);
*** ../vim-8.2.1271/src/proto/vim9compile.pro   2020-07-19 14:41:54.625623029 
+0200
--- src/proto/vim9compile.pro   2020-07-22 21:40:46.066532986 +0200
***************
*** 1,9 ****
  /* vim9compile.c */
  int check_defined(char_u *p, size_t len, cctx_T *cctx);
  void clear_type_list(garray_T *gap);
! type_T *typval2type(typval_T *tv);
  int check_type(type_T *expected, type_T *actual, int give_msg);
- int check_argtype(type_T *expected, typval_T *actual_tv);
  int check_compare_types(exptype_T type, typval_T *tv1, typval_T *tv2);
  char_u *skip_type(char_u *start);
  type_T *parse_type(char_u **arg, garray_T *type_gap);
--- 1,10 ----
  /* vim9compile.c */
  int check_defined(char_u *p, size_t len, cctx_T *cctx);
  void clear_type_list(garray_T *gap);
! 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 check_type(type_T *expected, type_T *actual, int give_msg);
  int check_compare_types(exptype_T type, typval_T *tv1, typval_T *tv2);
  char_u *skip_type(char_u *start);
  type_T *parse_type(char_u **arg, garray_T *type_gap);
*** ../vim-8.2.1271/src/vim9script.c    2020-07-12 17:07:01.020810937 +0200
--- src/vim9script.c    2020-07-22 21:37:19.427227115 +0200
***************
*** 557,563 ****
                semsg(_(e_readonlyvar), name);
                return FAIL;
            }
!           return check_type(sv->sv_type, typval2type(value), TRUE);
        }
      }
      iemsg("check_script_var_type(): not found");
--- 557,563 ----
                semsg(_(e_readonlyvar), name);
                return FAIL;
            }
!           return check_typval_type(sv->sv_type, value);
        }
      }
      iemsg("check_script_var_type(): not found");
*** ../vim-8.2.1271/src/vim9execute.c   2020-07-21 21:30:55.015536477 +0200
--- src/vim9execute.c   2020-07-22 21:40:41.358548945 +0200
***************
*** 737,743 ****
      for (idx = 0; idx < argc; ++idx)
      {
        if (ufunc->uf_arg_types != NULL && idx < ufunc->uf_args.ga_len
!               && check_argtype(ufunc->uf_arg_types[idx], &argv[idx]) == FAIL)
            goto failed_early;
        copy_tv(&argv[idx], STACK_TV_BOT(0));
        ++ectx.ec_stack.ga_len;
--- 737,744 ----
      for (idx = 0; idx < argc; ++idx)
      {
        if (ufunc->uf_arg_types != NULL && idx < ufunc->uf_args.ga_len
!               && check_typval_type(ufunc->uf_arg_types[idx], &argv[idx])
!                                                                      == FAIL)
            goto failed_early;
        copy_tv(&argv[idx], STACK_TV_BOT(0));
        ++ectx.ec_stack.ga_len;
*** ../vim-8.2.1271/src/testdir/test_vim9_script.vim    2020-07-22 
18:17:04.235863872 +0200
--- src/testdir/test_vim9_script.vim    2020-07-22 21:01:04.622022991 +0200
***************
*** 29,34 ****
--- 29,37 ----
    call CheckDefFailure(['let x:string = "x"'], 'E1069:')
    call CheckDefFailure(['let a:string = "x"'], 'E1069:')
  
+   let nr: number = 1234
+   call CheckDefFailure(['let nr: number = "asdf"'], 'E1013:')
+ 
    let a: number = 6 #comment
    assert_equal(6, a)
  
*** ../vim-8.2.1271/src/version.c       2020-07-22 20:16:08.071900823 +0200
--- src/version.c       2020-07-22 21:01:21.653960525 +0200
***************
*** 756,757 ****
--- 756,759 ----
  {   /* Add new patch number below this line */
+ /**/
+     1272,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
59. Your wife says communication is important in a marriage...so you buy
    another computer and install a second phone line so the two of you can
    chat.

 /// 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/202007221945.06MJjfWT1101088%40masaka.moolenaar.net.

Raspunde prin e-mail lui