Patch 9.0.1338
Problem:    :defcompile and :disassemble can't find class method. (Ernie Rael)
Solution:   Make a class name and class.method name work. (closes #11984)
Files:      src/vim.h, src/eval.c, src/structs.h, src/userfunc.c,
            src/proto/userfunc.pro, src/testdir/test_vim9_class.vim


*** ../vim-9.0.1337/src/vim.h   2023-02-21 14:27:34.528360386 +0000
--- src/vim.h   2023-02-21 18:08:02.474869088 +0000
***************
*** 2722,2727 ****
--- 2722,2728 ----
  #define GLV_NO_DECL   TFN_NO_DECL     // assignment without :var or :let
  #define GLV_COMPILING TFN_COMPILING   // variable may be defined later
  #define GLV_ASSIGN_WITH_OP TFN_ASSIGN_WITH_OP // assignment with operator
+ #define GLV_PREFER_FUNC       0x10000         // prefer function above 
variable
  
  #define DO_NOT_FREE_CNT 99999 // refcount for dict or list that should not
                                // be freed.
*** ../vim-9.0.1337/src/eval.c  2023-01-30 21:12:30.547422897 +0000
--- src/eval.c  2023-02-21 18:32:15.514674091 +0000
***************
*** 1529,1573 ****
            if (cl != NULL)
            {
                lp->ll_valtype = NULL;
!               int count = v_type == VAR_OBJECT ? cl->class_obj_member_count
!                                               : cl->class_class_member_count;
!               ocmember_T *members = v_type == VAR_OBJECT
!                                                    ? cl->class_obj_members
!                                                    : cl->class_class_members;
!               for (int i = 0; i < count; ++i)
                {
!                   ocmember_T *om = members + i;
!                   if (STRNCMP(om->ocm_name, key, p - key) == 0
!                                              && om->ocm_name[p - key] == NUL)
                    {
!                       switch (om->ocm_access)
                        {
!                           case ACCESS_PRIVATE:
!                                   semsg(_(e_cannot_access_private_member_str),
!                                                                om->ocm_name);
!                                   return NULL;
!                           case ACCESS_READ:
!                                   if (!(flags & GLV_READ_ONLY))
!                                   {
!                                       semsg(_(e_member_is_not_writable_str),
                                                                 om->ocm_name);
                                        return NULL;
!                                   }
!                                   break;
!                           case ACCESS_ALL:
!                                   break;
!                       }
  
!                       lp->ll_valtype = om->ocm_type;
  
!                       if (v_type == VAR_OBJECT)
!                           lp->ll_tv = ((typval_T *)(
                                            lp->ll_tv->vval.v_object + 1)) + i;
!                       else
!                           lp->ll_tv = &cl->class_members_tv[i];
!                       break;
                    }
                }
                if (lp->ll_valtype == NULL)
                {
                    if (v_type == VAR_OBJECT)
--- 1529,1609 ----
            if (cl != NULL)
            {
                lp->ll_valtype = NULL;
! 
!               if (flags & GLV_PREFER_FUNC)
                {
!                   // First look for a function with this name.
!                   // round 1: class functions (skipped for an object)
!                   // round 2: object methods
!                   for (int round = v_type == VAR_OBJECT ? 2 : 1;
!                                                          round <= 2; ++round)
                    {
!                       int count = round == 1
!                                           ? cl->class_class_function_count
!                                           : cl->class_obj_method_count;
!                       ufunc_T **funcs = round == 1
!                                           ? cl->class_class_functions
!                                           : cl->class_obj_methods;
!                       for (int i = 0; i < count; ++i)
                        {
!                           ufunc_T *fp = funcs[i];
!                           char_u *ufname = (char_u *)fp->uf_name;
!                           if (STRNCMP(ufname, key, p - key) == 0
!                                                    && ufname[p - key] == NUL)
!                           {
!                               lp->ll_ufunc = fp;
!                               lp->ll_valtype = fp->uf_func_type;
!                               round = 3;
!                               break;
!                           }
!                       }
!                   }
!               }
! 
!               if (lp->ll_valtype == NULL)
!               {
!                   int count = v_type == VAR_OBJECT
!                                           ? cl->class_obj_member_count
!                                           : cl->class_class_member_count;
!                   ocmember_T *members = v_type == VAR_OBJECT
!                                           ? cl->class_obj_members
!                                           : cl->class_class_members;
!                   for (int i = 0; i < count; ++i)
!                   {
!                       ocmember_T *om = members + i;
!                       if (STRNCMP(om->ocm_name, key, p - key) == 0
!                                              && om->ocm_name[p - key] == NUL)
!                       {
!                           switch (om->ocm_access)
!                           {
!                               case ACCESS_PRIVATE:
!                                       
semsg(_(e_cannot_access_private_member_str),
                                                                 om->ocm_name);
                                        return NULL;
!                               case ACCESS_READ:
!                                       if ((flags & GLV_READ_ONLY) == 0)
!                                       {
!                                           
semsg(_(e_member_is_not_writable_str),
!                                                                om->ocm_name);
!                                           return NULL;
!                                       }
!                                       break;
!                               case ACCESS_ALL:
!                                       break;
!                           }
  
!                           lp->ll_valtype = om->ocm_type;
  
!                           if (v_type == VAR_OBJECT)
!                               lp->ll_tv = ((typval_T *)(
                                            lp->ll_tv->vval.v_object + 1)) + i;
!                           else
!                               lp->ll_tv = &cl->class_members_tv[i];
!                           break;
!                       }
                    }
                }
+ 
                if (lp->ll_valtype == NULL)
                {
                    if (v_type == VAR_OBJECT)
*** ../vim-9.0.1337/src/structs.h       2023-02-21 12:38:46.823436717 +0000
--- src/structs.h       2023-02-21 18:28:18.821945224 +0000
***************
*** 4521,4526 ****
--- 4521,4527 ----
      char_u    *ll_newkey;     // New key for Dict in alloc. mem or NULL.
      type_T    *ll_valtype;    // type expected for the value or NULL
      blob_T    *ll_blob;       // The Blob or NULL
+     ufunc_T   *ll_ufunc;      // The function or NULL
  } lval_T;
  
  // Structure used to save the current state.  Used when executing Normal mode
*** ../vim-9.0.1337/src/userfunc.c      2023-02-21 14:27:34.528360386 +0000
--- src/userfunc.c      2023-02-21 19:29:48.830436863 +0000
***************
*** 1037,1044 ****
                if (*p == '!')
                    p = skipwhite(p + 1);
                p += eval_fname_script(p);
!               vim_free(trans_function_name(&p, NULL, TRUE, 0, NULL,
!                                                                 NULL, NULL));
                if (*skipwhite(p) == '(')
                {
                    if (nesting == MAX_FUNC_NESTING - 1)
--- 1037,1043 ----
                if (*p == '!')
                    p = skipwhite(p + 1);
                p += eval_fname_script(p);
!               vim_free(trans_function_name(&p, NULL, TRUE, 0));
                if (*skipwhite(p) == '(')
                {
                    if (nesting == MAX_FUNC_NESTING - 1)
***************
*** 4041,4050 ****
      char_u    **pp,
      int               *is_global,
      int               skip,           // only find the end, don't evaluate
      int               flags,
      funcdict_T        *fdp,           // return: info about dictionary used
      partial_T **partial,      // return: partial of a FuncRef
!     type_T    **type)         // return: type of funcref if not NULL
  {
      char_u    *name = NULL;
      char_u    *start;
--- 4040,4065 ----
      char_u    **pp,
      int               *is_global,
      int               skip,           // only find the end, don't evaluate
+     int               flags)
+ {
+     return trans_function_name_ext(pp, is_global, skip, flags,
+           NULL, NULL, NULL, NULL);
+ }
+ 
+ /*
+  * trans_function_name() with extra arguments.
+  * "fdp", "partial", "type" and "ufunc" can be NULL.
+  */
+     char_u *
+ trans_function_name_ext(
+     char_u    **pp,
+     int               *is_global,
+     int               skip,           // only find the end, don't evaluate
      int               flags,
      funcdict_T        *fdp,           // return: info about dictionary used
      partial_T **partial,      // return: partial of a FuncRef
!     type_T    **type,         // return: type of funcref
!     ufunc_T   **ufunc)        // return: function
  {
      char_u    *name = NULL;
      char_u    *start;
***************
*** 4079,4085 ****
        start += lead;
  
      // Note that TFN_ flags use the same values as GLV_ flags.
!     end = get_lval(start, NULL, &lv, FALSE, skip, flags | GLV_READ_ONLY,
                                              lead > 2 ? 0 : FNE_CHECK_START);
      if (end == start || (vim9script && end != NULL
                                   && end[-1] == AUTOLOAD_CHAR && *end == '('))
--- 4094,4101 ----
        start += lead;
  
      // Note that TFN_ flags use the same values as GLV_ flags.
!     end = get_lval(start, NULL, &lv, FALSE, skip,
!                       flags | GLV_READ_ONLY | GLV_PREFER_FUNC,
                                              lead > 2 ? 0 : FNE_CHECK_START);
      if (end == start || (vim9script && end != NULL
                                   && end[-1] == AUTOLOAD_CHAR && *end == '('))
***************
*** 4105,4110 ****
--- 4121,4133 ----
        goto theend;
      }
  
+     if (lv.ll_ufunc != NULL)
+     {
+       *ufunc = lv.ll_ufunc;
+       name = vim_strsave(lv.ll_ufunc->uf_name);
+       goto theend;
+     }
+ 
      if (lv.ll_tv != NULL)
      {
        if (fdp != NULL)
***************
*** 4455,4462 ****
            CLEAR_POINTER(fudi);
      }
      else
!       saved = trans_function_name(&p, is_global, skip,
!                                                     flags, fudi, NULL, NULL);
      *name = p;
      return saved;
  }
--- 4478,4485 ----
            CLEAR_POINTER(fudi);
      }
      else
!       saved = trans_function_name_ext(&p, is_global, skip,
!                                               flags, fudi, NULL, NULL, NULL);
      *name = p;
      return saved;
  }
***************
*** 5330,5344 ****
      }
      else
      {
!       // First try finding a method in a class, find_func_by_name() will give
!       // an error if the function is not found.
        ufunc = find_class_func(&arg);
        if (ufunc != NULL)
            return ufunc;
  
!       fname = trans_function_name(&arg, &is_global, FALSE,
                      TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DECL,
!                     NULL, NULL, NULL);
      }
      if (fname == NULL)
      {
--- 5353,5372 ----
      }
      else
      {
!       // First try finding a method in a class, trans_function_name() will
!       // give an error if the function is not found.
        ufunc = find_class_func(&arg);
        if (ufunc != NULL)
            return ufunc;
  
!       fname = trans_function_name_ext(&arg, &is_global, FALSE,
                      TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DECL,
!                     NULL, NULL, NULL, &ufunc);
!       if (ufunc != NULL)
!       {
!           vim_free(fname);
!           return ufunc;
!       }
      }
      if (fname == NULL)
      {
***************
*** 5375,5387 ****
      void
  ex_defcompile(exarg_T *eap)
  {
-     ufunc_T   *ufunc;
- 
      if (*eap->arg != NUL)
      {
        compiletype_T compile_type = CT_NONE;
! 
!       ufunc = find_func_by_name(eap->arg, &compile_type);
        if (ufunc != NULL)
        {
            if (func_needs_compiling(ufunc, compile_type))
--- 5403,5412 ----
      void
  ex_defcompile(exarg_T *eap)
  {
      if (*eap->arg != NUL)
      {
        compiletype_T compile_type = CT_NONE;
!       ufunc_T *ufunc = find_func_by_name(eap->arg, &compile_type);
        if (ufunc != NULL)
        {
            if (func_needs_compiling(ufunc, compile_type))
***************
*** 5401,5407 ****
            if (!HASHITEM_EMPTY(hi))
            {
                --todo;
!               ufunc = HI2UF(hi);
                if (ufunc->uf_script_ctx.sc_sid == current_sctx.sc_sid
                        && ufunc->uf_def_status == UF_TO_BE_COMPILED
                        && (ufunc->uf_flags & FC_DEAD) == 0)
--- 5426,5432 ----
            if (!HASHITEM_EMPTY(hi))
            {
                --todo;
!               ufunc_T *ufunc = HI2UF(hi);
                if (ufunc->uf_script_ctx.sc_sid == current_sctx.sc_sid
                        && ufunc->uf_def_status == UF_TO_BE_COMPILED
                        && (ufunc->uf_flags & FC_DEAD) == 0)
***************
*** 5475,5481 ****
      flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD;
      if (no_deref)
        flag |= TFN_NO_DEREF;
!     p = trans_function_name(&nm, &is_global, FALSE, flag, NULL, NULL, NULL);
      nm = skipwhite(nm);
  
      // Only accept "funcname", "funcname ", "funcname (..." and
--- 5500,5506 ----
      flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD;
      if (no_deref)
        flag |= TFN_NO_DEREF;
!     p = trans_function_name(&nm, &is_global, FALSE, flag);
      nm = skipwhite(nm);
  
      // Only accept "funcname", "funcname ", "funcname (..." and
***************
*** 5494,5501 ****
      char_u    *p;
      int               is_global = FALSE;
  
!     p = trans_function_name(&nm, &is_global, FALSE,
!                                         TFN_INT|TFN_QUIET, NULL, NULL, NULL);
  
      if (p != NULL && *nm == NUL
                       && (!check || translated_function_exists(p, is_global)))
--- 5519,5525 ----
      char_u    *p;
      int               is_global = FALSE;
  
!     p = trans_function_name(&nm, &is_global, FALSE, TFN_INT|TFN_QUIET);
  
      if (p != NULL && *nm == NUL
                       && (!check || translated_function_exists(p, is_global)))
***************
*** 5631,5638 ****
      int               is_global = FALSE;
  
      p = eap->arg;
!     name = trans_function_name(&p, &is_global, eap->skip, 0, &fudi,
!                                                                  NULL, NULL);
      vim_free(fudi.fd_newkey);
      if (name == NULL)
      {
--- 5655,5662 ----
      int               is_global = FALSE;
  
      p = eap->arg;
!     name = trans_function_name_ext(&p, &is_global, eap->skip, 0, &fudi,
!                                                            NULL, NULL, NULL);
      vim_free(fudi.fd_newkey);
      if (name == NULL)
      {
***************
*** 6166,6173 ****
        return;
      }
  
!     tofree = trans_function_name(&arg, NULL, eap->skip, TFN_INT,
!                             &fudi, &partial, vim9script ? &type : NULL);
      if (fudi.fd_newkey != NULL)
      {
        // Still need to give an error message for missing key.
--- 6190,6197 ----
        return;
      }
  
!     tofree = trans_function_name_ext(&arg, NULL, eap->skip, TFN_INT,
!                            &fudi, &partial, vim9script ? &type : NULL, NULL);
      if (fudi.fd_newkey != NULL)
      {
        // Still need to give an error message for missing key.
*** ../vim-9.0.1337/src/proto/userfunc.pro      2023-02-18 14:42:40.113005575 
+0000
--- src/proto/userfunc.pro      2023-02-21 19:29:52.086440237 +0000
***************
*** 41,47 ****
  int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, 
typval_T *argvars_in, funcexe_T *funcexe);
  int call_simple_func(char_u *funcname, int len, typval_T *rettv);
  char_u *printable_func_name(ufunc_T *fp);
! char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, 
funcdict_T *fdp, partial_T **partial, type_T **type);
  char_u *get_scriptlocal_funcname(char_u *funcname);
  char_u *alloc_printable_func_name(char_u *fname);
  char_u *save_function_name(char_u **name, int *is_global, int skip, int 
flags, funcdict_T *fudi);
--- 41,48 ----
  int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, 
typval_T *argvars_in, funcexe_T *funcexe);
  int call_simple_func(char_u *funcname, int len, typval_T *rettv);
  char_u *printable_func_name(ufunc_T *fp);
! char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags);
! char_u *trans_function_name_ext(char_u **pp, int *is_global, int skip, int 
flags, funcdict_T *fdp, partial_T **partial, type_T **type, ufunc_T **ufunc);
  char_u *get_scriptlocal_funcname(char_u *funcname);
  char_u *alloc_printable_func_name(char_u *fname);
  char_u *save_function_name(char_u **name, int *is_global, int skip, int 
flags, funcdict_T *fudi);
*** ../vim-9.0.1337/src/testdir/test_vim9_class.vim     2023-02-18 
18:38:33.375180762 +0000
--- src/testdir/test_vim9_class.vim     2023-02-21 19:53:45.180041011 +0000
***************
*** 842,847 ****
--- 842,875 ----
    v9.CheckScriptSuccess(lines)
  enddef
  
+ def Test_class_defcompile()
+   var lines =<< trim END
+       vim9script
+ 
+       class C
+           def Fo(i: number): string
+               return i
+           enddef
+       endclass
+ 
+       defcompile C.Fo
+   END
+   v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got 
number')
+ 
+   lines =<< trim END
+       vim9script
+ 
+       class C
+           static def Fc(): number
+             return 'x'
+           enddef
+       endclass
+ 
+       defcompile C.Fc
+   END
+   v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected number but got 
string')
+ enddef
+ 
  def Test_class_object_to_string()
    var lines =<< trim END
        vim9script
*** ../vim-9.0.1337/src/version.c       2023-02-21 15:18:47.097841611 +0000
--- src/version.c       2023-02-21 19:54:16.304005842 +0000
***************
*** 697,698 ****
--- 697,700 ----
  {   /* Add new patch number below this line */
+ /**/
+     1338,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
165. You have a web page burned into your glasses

 /// Bram Moolenaar -- b...@moolenaar.net -- 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 vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20230221195550.44E3B1C03AF%40moolenaar.net.

Raspunde prin e-mail lui