patch 9.1.1274: Vim9: no support for object<type> as variable type Commit: https://github.com/vim/vim/commit/6fa62085ffbfb3c69636da857574a017783f0410 Author: Yegappan Lakshmanan <yegap...@yahoo.com> Date: Thu Apr 3 21:26:34 2025 +0200
patch 9.1.1274: Vim9: no support for object<type> as variable type Problem: Vim9: no support for object<type> as variable type Solution: add support for object<type> (Yegappan Lakshmanan) closes: #17041 Signed-off-by: Yegappan Lakshmanan <yegap...@yahoo.com> Signed-off-by: Christian Brabandt <c...@256bit.org> diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt index 0e9a5080f..b7b2bcc5f 100644 --- a/runtime/doc/version9.txt +++ b/runtime/doc/version9.txt @@ -1,4 +1,4 @@ -*version9.txt* For Vim version 9.1. Last change: 2025 Mar 27 +*version9.txt* For Vim version 9.1. Last change: 2025 Apr 03 VIM REFERENCE MANUAL by Bram Moolenaar @@ -41553,6 +41553,8 @@ Enum support for Vim9 script |:enum| Support for protected _new() method +Add support for object<{type}> as variable data type |vim9-types| + Diff mode ~ --------- Include the "linematch" algorithm for the 'diffopt' setting. This aligns diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index d06c250a3..54fb8f333 100644 --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -1,4 +1,4 @@ -*vim9.txt* For Vim version 9.1. Last change: 2025 Mar 23 +*vim9.txt* For Vim version 9.1. Last change: 2025 Apr 03 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1467,6 +1467,7 @@ The following builtin types are supported: blob list<{type}> dict<{type}> + object<{type}> job channel tuple<{type}> diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim index c6d93b2b7..4b6cb81bb 100644 --- a/src/testdir/test_vim9_class.vim +++ b/src/testdir/test_vim9_class.vim @@ -12808,4 +12808,178 @@ def Test_dict_of_objects() v9.CheckSourceSuccess(lines) enddef +" Test for using the type() and typename() functions with a variable of type +" object +def Test_type_typename_funcs_with_object_variable() + var lines =<< trim END + vim9script + + class A + endclass + + class B + endclass + + var o1: object<any> + assert_equal([13, 'object<any>'], [type(o1), typename(o1)]) + + var o2: object<A> + assert_equal([13, 'object<any>'], [type(o2), typename(o2)]) + + var o3: A + assert_equal([13, 'object<any>'], [type(o3), typename(o3)]) + + var o4 = A.new() + assert_equal([13, 'object<A>'], [type(o4), typename(o4)]) + + var l = [A.new(), B.new()] + assert_equal([13, 'object<B>'], [type(l[1]), typename(l[1])]) + + var d = {o_a: A.new(), o_b: B.new()} + assert_equal([13, 'object<B>'], [type(d.o_b), typename(d.o_b)]) + END + v9.CheckSourceSuccess(lines) +enddef + +" Test for object<any> type +def Test_object_any_type() + # assigning different objects to variable of type object<any> + var lines =<< trim END + vim9script + class A + endclass + class B + endclass + var x: object<any> + x = A.new() + assert_true(instanceof(x, A)) + x = B.new() + assert_true(instanceof(x, B)) + x = null_object + assert_true(instanceof(x, null_class)) + END + v9.CheckSourceSuccess(lines) + + # Use a list of object<any> variable + lines =<< trim END + vim9script + class A + endclass + class B + endclass + var l: list<object<any>> + l->add(A.new()) + l->add(B.new()) + assert_true(instanceof(l[0], A)) + assert_true(instanceof(l[1], B)) + END + v9.CheckSourceSuccess(lines) + + # Using object<any> as a function argument type and the return type + lines =<< trim END + vim9script + class A + endclass + class B + endclass + def Fn(x: object<any>): object<any> + return x + enddef + assert_true(instanceof(Fn(A.new()), A)) + assert_true(instanceof(Fn(B.new()), B)) + END + + # Try assigning a different type of value to a object<any> variable + lines =<< trim END + var x: object<any> = [] + END + v9.CheckSourceDefAndScriptFailure(lines, ['E1012: Type mismatch; expected object<any> but got list<any>', 'E1012: Type mismatch; expected object<any> but got list<any>']) + + # Try assigning a different type of value to a object<any> variable + lines =<< trim END + var x: object<any> + x = 0z10 + END + v9.CheckSourceDefAndScriptFailure(lines, ['E1012: Type mismatch; expected object<any> but got blob', 'E1012: Type mismatch; expected object<any> but got blob']) + + # Try adding a different type of value to a list<object<any>> variable + lines =<< trim END + var x: list<object<any>> + x->add({}) + END + v9.CheckSourceDefAndScriptFailure(lines, ['E1012: Type mismatch; expected object<any> but got dict<any>', 'E1012: Type mismatch; expected object<any> but got dict<any>']) + + # Try adding a different type of value to a dict<object<any>> variable + lines =<< trim END + var x: dict<object<any>> + x['a'] = {} + END + v9.CheckSourceDefAndScriptFailure(lines, ['E1012: Type mismatch; expected object<any> but got dict<any>', 'E1012: Type mismatch; expected object<any> but got dict<any>']) +enddef + +" Test for object<{class}> type +def Test_object_of_class_type() + var lines =<< trim END + vim9script + class A + endclass + var x: object<A> + x = A.new() + assert_true(instanceof(x, A)) + var y: object<A> = A.new() + assert_true(instanceof(y, A)) + END + v9.CheckSourceSuccess(lines) + + lines =<< trim END + vim9script + class A + endclass + class B + endclass + var x: object<A> + x = B.new() + END + v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected object<A> but got object<B>') + + lines =<< trim END + vim9script + class A + endclass + class B + endclass + def Fn(x: object<A>): object<B> + return B.new() + enddef + assert_true(instanceof(Fn(A.new()), B)) + END + v9.CheckSourceSuccess(lines) + + lines =<< trim END + var x: object + END + v9.CheckSourceDefAndScriptFailure(lines, ['E1008: Missing <type> after object', 'E1008: Missing <type> after object']) + + lines =<< trim END + var x: object <any> + END + v9.CheckSourceDefAndScriptFailure(lines, ['E1068: No white space allowed before ''<'': <any>', 'E1068: No white space allowed before ''<'': <any>']) + + lines =<< trim END + var x: object<any + END + v9.CheckSourceDefAndScriptFailure(lines, ['E1009: Missing > after type: <any', 'E1009: Missing > after type: <any']) + + lines =<< trim END + var x: object<any,any> + END + v9.CheckSourceDefFailure(lines, 'E1009: Missing > after type: <any,any>') + + lines =<< trim END + vim9script + var x: object<any,any> + END + v9.CheckSourceFailure(lines, 'E488: Trailing characters: ,any>') +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/version.c b/src/version.c index e00e0077c..42576d1e8 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1274, /**/ 1273, /**/ diff --git a/src/vim9class.c b/src/vim9class.c index 5249f40de..560c5ae28 100644 --- a/src/vim9class.c +++ b/src/vim9class.c @@ -4132,7 +4132,12 @@ f_instanceof(typval_T *argvars, typval_T *rettv) return; if (object_tv->vval.v_object == NULL) + { + if (classinfo_tv->vval.v_class == NULL) + // consider null_object as an instance of null_class + rettv->vval.v_number = VVAL_TRUE; return; + } for (; classinfo_tv->v_type != VAR_UNKNOWN; ++classinfo_tv) { diff --git a/src/vim9type.c b/src/vim9type.c index 2f8509587..a3881c9b1 100644 --- a/src/vim9type.c +++ b/src/vim9type.c @@ -1784,6 +1784,63 @@ on_err: return ret_type; } +/* + * Parse a "object" type at "*arg" and advance over it. + * When "give_error" is TRUE give error messages, otherwise be quiet. + * Return NULL for failure. + */ + static type_T * +parse_type_object(char_u **arg, garray_T *type_gap, int give_error) +{ + char_u *arg_start = *arg; + type_T *object_type; + int prev_called_emsg = called_emsg; + + // object<X> or object<any> + if (**arg != '<') + { + if (give_error) + { + if (*skipwhite(*arg) == '<') + semsg(_(e_no_white_space_allowed_before_str_str), "<", *arg); + else + semsg(_(e_missing_type_after_str), "object"); + } + + // only "object" is specified + return NULL; + } + + // skip spaces following "object<" + *arg = skipwhite(*arg + 1); + + object_type = parse_type(arg, type_gap, give_error); + if (object_type == NULL) + return NULL; + + *arg = skipwhite(*arg); + if (**arg != '>' && called_emsg == prev_called_emsg) + { + if (give_error) + semsg(_(e_missing_gt_after_type_str), arg_start); + return NULL; + } + ++*arg; + + if (object_type->tt_type == VAR_ANY) + return &t_object_any; + + if (object_type->tt_type != VAR_OBJECT) + { + // specified type is not a class + if (give_error) + semsg(_(e_class_name_not_found_str), arg_start); + return NULL; + } + + return object_type; +} + /* * Parse a user defined type at "*arg" and advance over it. * It can be a class or an interface or a typealias name, possibly imported. @@ -1932,6 +1989,13 @@ parse_type(char_u **arg, garray_T *type_gap, int give_error) return &t_number; } break; + case 'o': + if (len == 6 && STRNCMP(*arg, "object", len) == 0) + { + *arg += len; + return parse_type_object(arg, type_gap, give_error); + } + break; case 's': if (len == 6 && STRNCMP(*arg, "string", len) == 0) { -- -- 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 visit https://groups.google.com/d/msgid/vim_dev/E1u0QUq-00G4f0-42%40256bit.org.