To: vim_dev@googlegroups.com Subject: Patch 9.0.1338 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 -- Bram@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 ///