Patch 9.0.1322
Problem:    Crash when indexing "any" which is an object.
Solution:   Check the index is a number.  Do not check the member type of an
            object.  (closes #12019)
Files:      src/vim9execute.c, src/vim9compile.c,
            src/testdir/test_vim9_class.vim


*** ../vim-9.0.1321/src/vim9execute.c   2023-02-18 14:42:40.117005581 +0000
--- src/vim9execute.c   2023-02-18 17:34:54.853153029 +0000
***************
*** 2126,2134 ****
--- 2126,2138 ----
      vartype_T dest_type = iptr->isn_arg.storeindex.si_vartype;
      typval_T  *tv;
      typval_T  *tv_idx = STACK_TV_BOT(-2);
+     long      lidx = 0;
      typval_T  *tv_dest = STACK_TV_BOT(-1);
      int               status = OK;
  
+     if (tv_idx->v_type == VAR_NUMBER)
+       lidx = (long)tv_idx->vval.v_number;
+ 
      // Stack contains:
      // -3 value to be stored
      // -2 index
***************
*** 2140,2146 ****
        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)
        {
            emsg(_(e_number_expected));
            status = FAIL;
--- 2144,2184 ----
        dest_type = tv_dest->v_type;
        if (dest_type == VAR_DICT)
            status = do_2string(tv_idx, TRUE, FALSE);
!       else if (dest_type == VAR_OBJECT && tv_idx->v_type == VAR_STRING)
!       {
!           // Need to get the member index now that the class is known.
!           object_T *obj = tv_dest->vval.v_object;
!           class_T *cl = obj->obj_class;
!           char_u  *member = tv_idx->vval.v_string;
! 
!           ocmember_T *m = NULL;
!           for (int i = 0; i < cl->class_obj_member_count; ++i)
!           {
!               m = &cl->class_obj_members[i];
!               if (STRCMP(member, m->ocm_name) == 0)
!               {
!                   if (*member == '_')
!                   {
!                       semsg(_(e_cannot_access_private_member_str),
!                                                                 m->ocm_name);
!                       status = FAIL;
!                   }
! 
!                   lidx = i;
!                   break;
!               }
!               m = NULL;
!           }
! 
!           if (m == NULL)
!           {
!               semsg(_(e_member_not_found_on_object_str_str),
!                                                      cl->class_name, member);
!               status = FAIL;
!           }
!       }
!       else if ((dest_type == VAR_LIST || dest_type == VAR_OBJECT)
!               && tv_idx->v_type != VAR_NUMBER)
        {
            emsg(_(e_number_expected));
            status = FAIL;
***************
*** 2151,2157 ****
      {
        if (dest_type == VAR_LIST)
        {
-           long            lidx = (long)tv_idx->vval.v_number;
            list_T          *list = tv_dest->vval.v_list;
  
            if (list == NULL)
--- 2189,2194 ----
***************
*** 2224,2230 ****
        }
        else if (dest_type == VAR_BLOB)
        {
-           long            lidx = (long)tv_idx->vval.v_number;
            blob_T          *blob = tv_dest->vval.v_blob;
            varnumber_T     nr;
            int             error = FALSE;
--- 2261,2266 ----
***************
*** 2255,2272 ****
        }
        else if (dest_type == VAR_CLASS || dest_type == VAR_OBJECT)
        {
-           long            idx = (long)tv_idx->vval.v_number;
            object_T        *obj = tv_dest->vval.v_object;
            typval_T        *otv = (typval_T *)(obj + 1);
  
            class_T         *itf = iptr->isn_arg.storeindex.si_class;
            if (itf != NULL)
                // convert interface member index to class member index
!               idx = object_index_from_itf_index(itf, FALSE,
!                                                         idx, obj->obj_class);
  
!           clear_tv(&otv[idx]);
!           otv[idx] = *tv;
        }
        else
        {
--- 2291,2307 ----
        }
        else if (dest_type == VAR_CLASS || dest_type == VAR_OBJECT)
        {
            object_T        *obj = tv_dest->vval.v_object;
            typval_T        *otv = (typval_T *)(obj + 1);
  
            class_T         *itf = iptr->isn_arg.storeindex.si_class;
            if (itf != NULL)
                // convert interface member index to class member index
!               lidx = object_index_from_itf_index(itf, FALSE,
!                                                        lidx, obj->obj_class);
  
!           clear_tv(&otv[lidx]);
!           otv[lidx] = *tv;
        }
        else
        {
*** ../vim-9.0.1321/src/vim9compile.c   2023-02-08 20:55:23.932100744 +0000
--- src/vim9compile.c   2023-02-18 18:34:34.787068740 +0000
***************
*** 2011,2023 ****
        size_t      varlen = lhs->lhs_varlen;
        int         c = var_start[varlen];
        int         lines_len = cctx->ctx_ufunc->uf_lines.ga_len;
-       char_u      *p = var_start;
        int         res;
  
        // Evaluate "ll[expr]" of "ll[expr][idx]".  End the line with a NUL and
        // limit the lines array length to avoid skipping to a following line.
        var_start[varlen] = NUL;
        cctx->ctx_ufunc->uf_lines.ga_len = cctx->ctx_lnum + 1;
        res = compile_expr0(&p, cctx);
        var_start[varlen] = c;
        cctx->ctx_ufunc->uf_lines.ga_len = lines_len;
--- 2011,2023 ----
        size_t      varlen = lhs->lhs_varlen;
        int         c = var_start[varlen];
        int         lines_len = cctx->ctx_ufunc->uf_lines.ga_len;
        int         res;
  
        // Evaluate "ll[expr]" of "ll[expr][idx]".  End the line with a NUL and
        // limit the lines array length to avoid skipping to a following line.
        var_start[varlen] = NUL;
        cctx->ctx_ufunc->uf_lines.ga_len = cctx->ctx_lnum + 1;
+       char_u *p = var_start;
        res = compile_expr0(&p, cctx);
        var_start[varlen] = c;
        cctx->ctx_ufunc->uf_lines.ga_len = lines_len;
***************
*** 2031,2040 ****
  
        lhs->lhs_type = cctx->ctx_type_stack.ga_len == 0 ? &t_void
                                                  : get_type_on_stack(cctx, 0);
!       // now we can properly check the type
!       if (rhs_type != NULL && lhs->lhs_type->tt_member != NULL
                && rhs_type != &t_void
!               && need_type(rhs_type, lhs->lhs_type->tt_member, FALSE,
                                            -2, 0, cctx, FALSE, FALSE) == FAIL)
            return FAIL;
      }
--- 2031,2045 ----
  
        lhs->lhs_type = cctx->ctx_type_stack.ga_len == 0 ? &t_void
                                                  : get_type_on_stack(cctx, 0);
!       // Now we can properly check the type.  The variable is indexed, thus
!       // we need the member type.  For a class or object we don't know the
!       // type yet, it depends on what member is used.
!       vartype_T vartype = lhs->lhs_type->tt_type;
!       type_T *member_type = lhs->lhs_type->tt_member;
!       if (rhs_type != NULL && member_type != NULL
!               && vartype != VAR_OBJECT && vartype != VAR_CLASS
                && rhs_type != &t_void
!               && need_type(rhs_type, member_type, FALSE,
                                            -2, 0, cctx, FALSE, FALSE) == FAIL)
            return FAIL;
      }
*** ../vim-9.0.1321/src/testdir/test_vim9_class.vim     2023-02-18 
14:42:40.117005581 +0000
--- src/testdir/test_vim9_class.vim     2023-02-18 17:38:44.469231743 +0000
***************
*** 253,258 ****
--- 253,308 ----
    v9.CheckScriptSuccess(lines)
  enddef
  
+ def Test_member_any_used_as_object()
+   var lines =<< trim END
+       vim9script
+ 
+       class Inner
+         this.value: number = 0
+       endclass
+ 
+       class Outer
+         this.inner: any
+       endclass
+ 
+       def F(outer: Outer)
+         outer.inner.value = 1
+       enddef
+ 
+       var inner_obj = Inner.new(0)
+       var outer_obj = Outer.new(inner_obj)
+       F(outer_obj)
+       assert_equal(1, inner_obj.value)
+   END
+   v9.CheckScriptSuccess(lines)
+ 
+   lines =<< trim END
+       vim9script
+ 
+       class Inner
+         this.value: number = 0
+       endclass
+ 
+       class Outer
+         this.inner: Inner
+       endclass
+ 
+       def F(outer: Outer)
+         outer.inner.value = 1
+       enddef
+ 
+       def Test_assign_to_nested_typed_member()
+         var inner = Inner.new(0)
+         var outer = Outer.new(inner)
+         F(outer)
+         assert_equal(1, inner.value)
+       enddef
+ 
+       Test_assign_to_nested_typed_member()
+   END
+   v9.CheckScriptSuccess(lines)
+ enddef
+ 
  def Test_assignment_with_operator()
    var lines =<< trim END
        vim9script
*** ../vim-9.0.1321/src/version.c       2023-02-18 15:31:49.134360548 +0000
--- src/version.c       2023-02-18 17:13:26.115323294 +0000
***************
*** 697,698 ****
--- 697,700 ----
  {   /* Add new patch number below this line */
+ /**/
+     1322,
  /**/

-- 
Fingers not found - Pound head on keyboard to continue.

 /// 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/20230218183904.BC36E1C0164%40moolenaar.net.

Raspunde prin e-mail lui