To: vim_dev@googlegroups.com Subject: Patch 9.0.1054 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.1054 Problem: Object member can't get type from initializer. Solution: If there is no type specified try to use the type of the initializer. Check for a valid type. Files: src/vim9class.c, src/errors.h, src/vim9type.c, src/proto/vim9type.pro, src/testdir/test_vim9_class.vim *** ../vim-9.0.1053/src/vim9class.c 2022-12-13 18:42:19.749879633 +0000 --- src/vim9class.c 2022-12-13 21:00:20.555936418 +0000 *************** *** 125,167 **** char_u *varname_end = to_name_end(varname, FALSE); char_u *colon = skipwhite(varname_end); ! // TODO: accept initialization and figure out type from it ! if (*colon != ':') { ! emsg(_(e_type_or_initialization_required)); ! break; ! } ! if (VIM_ISWHITE(*varname_end)) ! { ! semsg(_(e_no_white_space_allowed_before_colon_str), varname); ! break; } ! if (!VIM_ISWHITE(colon[1])) { ! semsg(_(e_white_space_required_after_str_str), ":", varname); break; } ! char_u *type_arg = skipwhite(colon + 1); ! type_T *type = parse_type(&type_arg, &type_list, TRUE); ! if (type == NULL) ! break; ! ! char_u *expr_start = skipwhite(type_arg); ! if (*expr_start == '=' && (!VIM_ISWHITE(expr_start[-1]) ! || !VIM_ISWHITE(expr_start[1]))) { ! semsg(_(e_white_space_required_before_and_after_str_at_str), "=", type_arg); ! break; ! } ! expr_start = skipwhite(expr_start + 1); ! char_u *expr_end = expr_start; ! evalarg_T evalarg; ! init_evalarg(&evalarg); ! skip_expr(&expr_end, &evalarg); ! clear_evalarg(&evalarg, NULL); if (ga_grow(&objmembers, 1) == FAIL) break; --- 125,198 ---- char_u *varname_end = to_name_end(varname, FALSE); char_u *colon = skipwhite(varname_end); ! char_u *type_arg = colon; ! type_T *type = NULL; ! if (*colon == ':') { ! if (VIM_ISWHITE(*varname_end)) ! { ! semsg(_(e_no_white_space_allowed_before_colon_str), ! varname); ! break; ! } ! if (!VIM_ISWHITE(colon[1])) ! { ! semsg(_(e_white_space_required_after_str_str), ":", ! varname); ! break; ! } ! type_arg = skipwhite(colon + 1); ! type = parse_type(&type_arg, &type_list, TRUE); ! if (type == NULL) ! break; } ! ! char_u *expr_start = skipwhite(type_arg); ! char_u *expr_end = expr_start; ! if (type == NULL && *expr_start != '=') { ! emsg(_(e_type_or_initialization_required)); break; } ! if (*expr_start == '=') { ! if (!VIM_ISWHITE(expr_start[-1]) || !VIM_ISWHITE(expr_start[1])) ! { ! semsg(_(e_white_space_required_before_and_after_str_at_str), "=", type_arg); ! break; ! } ! expr_start = skipwhite(expr_start + 1); ! expr_end = expr_start; ! evalarg_T evalarg; ! fill_evalarg_from_eap(&evalarg, eap, FALSE); ! skip_expr(&expr_end, &evalarg); ! ! if (type == NULL) ! { ! // No type specified, use the type of the initializer. ! typval_T tv; ! tv.v_type = VAR_UNKNOWN; ! char_u *expr = expr_start; ! int res = eval0(expr, &tv, eap, &evalarg); ! ! if (res == OK) ! type = typval2type(&tv, get_copyID(), &type_list, ! TVTT_DO_MEMBER); ! if (type == NULL) ! { ! semsg(_(e_cannot_get_object_member_type_from_initializer_str), ! expr_start); ! clear_evalarg(&evalarg, NULL); ! break; ! } ! } ! clear_evalarg(&evalarg, NULL); ! } ! if (!valid_declaration_type(type)) ! break; if (ga_grow(&objmembers, 1) == FAIL) break; *** ../vim-9.0.1053/src/errors.h 2022-12-13 18:42:19.745879637 +0000 --- src/errors.h 2022-12-13 21:07:59.167945331 +0000 *************** *** 3374,3377 **** --- 3374,3381 ---- INIT(= N_("E1327: Object required, found %s")); EXTERN char e_constructor_default_value_must_be_vnone_str[] INIT(= N_("E1328: Constructor default value must be v:none: %s")); + EXTERN char e_cannot_get_object_member_type_from_initializer_str[] + INIT(= N_("E1329: Cannot get object member type from initializer: %s")); + EXTERN char e_invalid_type_for_object_member_str[] + INIT(= N_("E1330: Invalid type for object member: %s")); #endif *** ../vim-9.0.1053/src/vim9type.c 2022-12-13 13:42:32.179427634 +0000 --- src/vim9type.c 2022-12-13 21:09:35.995942904 +0000 *************** *** 425,430 **** --- 425,441 ---- return &t_number; if (tv->v_type == VAR_BOOL) return &t_bool; + if (tv->v_type == VAR_SPECIAL) + { + if (tv->vval.v_number == VVAL_NULL) + return &t_null; + if (tv->vval.v_number == VVAL_NONE) + return &t_none; + if (tv->vval.v_number == VVAL_TRUE + || tv->vval.v_number == VVAL_TRUE) + return &t_bool; + return &t_unknown; + } if (tv->v_type == VAR_STRING) return &t_string; if (tv->v_type == VAR_BLOB) *************** *** 620,625 **** --- 631,655 ---- } /* + * Return TRUE if "type" can be used for a variable declaration. + * Give an error and return FALSE if not. + */ + int + valid_declaration_type(type_T *type) + { + if (type->tt_type == VAR_SPECIAL // null, none + || type->tt_type == VAR_VOID) + { + char *tofree = NULL; + char *name = type_name(type, &tofree); + semsg(_(e_invalid_type_for_object_member_str), name); + vim_free(tofree); + return FALSE; + } + return TRUE; + } + + /* * Get a type_T for a typval_T, used for v: variables. * "type_list" is used to temporarily create types in. */ *** ../vim-9.0.1053/src/proto/vim9type.pro 2022-12-08 15:32:11.087034211 +0000 --- src/proto/vim9type.pro 2022-12-13 21:08:20.707944884 +0000 *************** *** 13,18 **** --- 13,19 ---- int type_any_or_unknown(type_T *type); int need_convert_to_bool(type_T *type, typval_T *tv); type_T *typval2type(typval_T *tv, int copyID, garray_T *type_gap, int flags); + int valid_declaration_type(type_T *type); type_T *typval2type_vimvar(typval_T *tv, garray_T *type_gap); int check_typval_arg_type(type_T *expected, typval_T *actual_tv, char *func_name, int arg_idx); int check_typval_type(type_T *expected, typval_T *actual_tv, where_T where); *** ../vim-9.0.1053/src/testdir/test_vim9_class.vim 2022-12-13 18:42:19.749879633 +0000 --- src/testdir/test_vim9_class.vim 2022-12-13 21:10:32.755941033 +0000 *************** *** 231,237 **** --- 231,288 ---- assert_equal("none", chris.education) END v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + class Person + this.name: string + this.age: number = 42 + this.education: string = "unknown" + + def new(this.name, this.age = v:none, this.education = v:none) + enddef + endclass + + var missing = Person.new() + END + v9.CheckScriptFailure(lines, 'E119:') + enddef + + def Test_class_object_member_inits() + var lines =<< trim END + vim9script + class TextPosition + this.lnum: number + this.col = 1 + this.addcol: number = 2 + endclass + + var pos = TextPosition.new() + assert_equal(0, pos.lnum) + assert_equal(1, pos.col) + assert_equal(2, pos.addcol) + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + class TextPosition + this.lnum + this.col = 1 + endclass + END + v9.CheckScriptFailure(lines, 'E1022:') + + lines =<< trim END + vim9script + class TextPosition + this.lnum = v:none + this.col = 1 + endclass + END + v9.CheckScriptFailure(lines, 'E1330:') enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker *** ../vim-9.0.1053/src/version.c 2022-12-13 18:42:19.749879633 +0000 --- src/version.c 2022-12-13 20:43:31.263950568 +0000 *************** *** 697,698 **** --- 697,700 ---- { /* Add new patch number below this line */ + /**/ + 1054, /**/ -- ### Hiroshima 45, Chernobyl 86, Windows 95 ### /// 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 ///