diff --git a/src/errors.h b/src/errors.h index 0d53fa84c..6184037df 100644 --- a/src/errors.h +++ b/src/errors.h @@ -3411,16 +3411,14 @@ EXTERN char e_public_member_name_cannot_start_with_underscore_str[] INIT(= N_("E1332: Public member name cannot start with underscore: %s")); EXTERN char e_cannot_access_private_member_str[] INIT(= N_("E1333: Cannot access private member: %s")); -EXTERN char e_object_member_not_found_str[] - INIT(= N_("E1334: Object member not found: %s")); EXTERN char e_member_is_not_writable_str[] INIT(= N_("E1335: Member is not writable: %s")); #endif EXTERN char e_internal_error_shortmess_too_long[] INIT(= "E1336: Internal error: shortmess too long"); #ifdef FEAT_EVAL -EXTERN char e_class_member_not_found_str[] - INIT(= N_("E1337: Class member not found: %s")); +EXTERN char e_class_member_str_not_found_in_class_str[] + INIT(= N_("E1337: Class member \"%s\" not found in class \"%s\"")); EXTERN char e_member_not_found_on_class_str_str[] INIT(= N_("E1338: Member not found on class \"%s\": %s")); #endif @@ -3488,7 +3486,6 @@ EXTERN char e_cannot_access_private_method_str[] INIT(= N_("E1366: Cannot access private method: %s")); EXTERN char e_member_str_of_interface_str_has_different_access[] INIT(= N_("E1367: Access level of member \"%s\" of interface \"%s\" is different")); - EXTERN char e_static_cannot_be_followed_by_this[] INIT(= N_("E1368: Static cannot be followed by \"this\" in a member name")); EXTERN char e_duplicate_member_str[] @@ -3501,6 +3498,16 @@ EXTERN char e_abstract_method_in_concrete_class[] INIT(= N_("E1372: Abstract method \"%s\" cannot be defined in a concrete class")); EXTERN char e_abstract_method_str_not_found[] INIT(= N_("E1373: Abstract method \"%s\" is not implemented")); +EXTERN char e_class_member_str_accessible_only_inside_class_str[] + INIT(= N_("E1374: Class member \"%s\" accessible only inside class \"%s\"")); +EXTERN char e_class_member_str_accessible_only_using_class_str[] + INIT(= N_("E1375: Class member \"%s\" accessible only using class \"%s\"")); +EXTERN char e_object_member_str_accessible_only_using_object_str[] + INIT(= N_("E1376: Object member \"%s\" accessible only using class \"%s\" object")); +EXTERN char e_static_member_not_supported_in_interface[] + INIT(= N_("E1377: Static member is not supported in an interface")); +EXTERN char e_method_str_of_class_str_has_different_access[] + INIT(= N_("E1378: Access level of method \"%s\" is different in class \"%s\"")); EXTERN char e_cannot_mix_positional_and_non_positional_str[] INIT(= N_("E1400: Cannot mix positional and non-positional arguments: %s")); EXTERN char e_fmt_arg_nr_unused_str[] @@ -3521,4 +3528,4 @@ EXTERN char e_aptypes_is_null_nr_str[] INIT(= "E1408: Internal error: ap_types or ap_types[idx] is NULL: %d: %s"); EXTERN char e_interface_static_direct_access_str[] INIT(= N_("E1409: Cannot directly access interface \"%s\" static member \"%s\"")); -// E1371 - E1399 unused +// E1376 - E1399 unused diff --git a/src/eval.c b/src/eval.c index dd7b8d8f3..523546957 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1596,10 +1596,7 @@ get_lval( if (lp->ll_valtype == NULL) { - if (v_type == VAR_OBJECT) - semsg(_(e_object_member_not_found_str), key); - else - semsg(_(e_class_member_not_found_str), key); + member_not_found_msg(cl, v_type, key, p - key); return NULL; } } diff --git a/src/proto/vim9class.pro b/src/proto/vim9class.pro index a61c40f23..1448f1915 100644 --- a/src/proto/vim9class.pro +++ b/src/proto/vim9class.pro @@ -26,6 +26,8 @@ int set_ref_in_classes(int copyID); void object_created(object_T *obj); void object_cleared(object_T *obj); int object_free_nonref(int copyID); +void method_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len); +void member_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len); void f_instanceof(typval_T *argvars, typval_T *rettv); int class_instance_of(class_T *cl, class_T *other_cl); /* vim: set ft=c : */ diff --git a/src/structs.h b/src/structs.h index 921409697..4a82c82e6 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1791,8 +1791,11 @@ struct ufunc_S def_status_T uf_def_status; // UF_NOT_COMPILED, UF_TO_BE_COMPILED, etc. int uf_dfunc_idx; // only valid if uf_def_status is UF_COMPILED - class_T *uf_class; // for object method and constructor; does not - // count for class_refcount + class_T *uf_class; // for class/object method and constructor; + // does not count for class_refcount. + // class of the object which is invoking this + // function. + class_T *uf_defclass; // class where this function is defined. garray_T uf_args; // arguments, including optional arguments garray_T uf_def_args; // default argument expressions diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim index be4eb2eb8..1796f5f72 100644 --- a/src/testdir/test_vim9_class.vim +++ b/src/testdir/test_vim9_class.vim @@ -8,56 +8,56 @@ def Test_class_basic() class NotWorking endclass END - v9.CheckScriptFailure(lines, 'E1316:') + v9.CheckSourceFailure(lines, 'E1316:') lines =<< trim END vim9script class notWorking endclass END - v9.CheckScriptFailure(lines, 'E1314:') + v9.CheckSourceFailure(lines, 'E1314:') lines =<< trim END vim9script class Not@working endclass END - v9.CheckScriptFailure(lines, 'E1315:') + v9.CheckSourceFailure(lines, 'E1315:') lines =<< trim END vim9script abstract noclass Something endclass END - v9.CheckScriptFailure(lines, 'E475:') + v9.CheckSourceFailure(lines, 'E475:') lines =<< trim END vim9script abstract classy Something endclass END - v9.CheckScriptFailure(lines, 'E475:') + v9.CheckSourceFailure(lines, 'E475:') lines =<< trim END vim9script class Something endcl END - v9.CheckScriptFailure(lines, 'E1065:') + v9.CheckSourceFailure(lines, 'E1065:') lines =<< trim END vim9script class Something endclass school's out END - v9.CheckScriptFailure(lines, 'E488:') + v9.CheckSourceFailure(lines, 'E488:') lines =<< trim END vim9script class Something endclass | echo 'done' END - v9.CheckScriptFailure(lines, 'E488:') + v9.CheckSourceFailure(lines, 'E488:') lines =<< trim END vim9script @@ -65,7 +65,7 @@ def Test_class_basic() this endclass END - v9.CheckScriptFailure(lines, 'E1317:') + v9.CheckSourceFailure(lines, 'E1317:') lines =<< trim END vim9script @@ -73,7 +73,7 @@ def Test_class_basic() this. endclass END - v9.CheckScriptFailure(lines, 'E1317:') + v9.CheckSourceFailure(lines, 'E1317:') lines =<< trim END vim9script @@ -81,7 +81,7 @@ def Test_class_basic() this .count endclass END - v9.CheckScriptFailure(lines, 'E1317:') + v9.CheckSourceFailure(lines, 'E1317:') lines =<< trim END vim9script @@ -89,7 +89,7 @@ def Test_class_basic() this. count endclass END - v9.CheckScriptFailure(lines, 'E1317:') + v9.CheckSourceFailure(lines, 'E1317:') lines =<< trim END vim9script @@ -98,7 +98,7 @@ def Test_class_basic() that.count endclass END - v9.CheckScriptFailure(lines, 'E1318: Not a valid command in a class: that.count') + v9.CheckSourceFailure(lines, 'E1318: Not a valid command in a class: that.count') lines =<< trim END vim9script @@ -106,7 +106,7 @@ def Test_class_basic() this.count endclass END - v9.CheckScriptFailure(lines, 'E1022:') + v9.CheckSourceFailure(lines, 'E1022:') lines =<< trim END vim9script @@ -117,7 +117,7 @@ def Test_class_basic() endclass var obj = Something.new() END - v9.CheckScriptFailure(lines, 'E1089:') + v9.CheckSourceFailure(lines, 'E1089:') lines =<< trim END vim9script @@ -125,7 +125,7 @@ def Test_class_basic() this.count : number endclass END - v9.CheckScriptFailure(lines, 'E1059:') + v9.CheckSourceFailure(lines, 'E1059:') lines =<< trim END vim9script @@ -133,7 +133,7 @@ def Test_class_basic() this.count:number endclass END - v9.CheckScriptFailure(lines, 'E1069:') + v9.CheckSourceFailure(lines, 'E1069:') # Test for unsupported comment specifier lines =<< trim END @@ -143,7 +143,7 @@ def Test_class_basic() #{ endclass END - v9.CheckScriptFailure(lines, 'E1170:') + v9.CheckSourceFailure(lines, 'E1170:') lines =<< trim END vim9script @@ -171,7 +171,7 @@ def Test_class_basic() assert_equal('class', typename(TextPosition)) assert_equal('object', typename(pos)) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # When referencing object methods, space cannot be used after a "." lines =<< trim END @@ -184,7 +184,7 @@ def Test_class_basic() var a = A.new() var v = a. Foo() END - v9.CheckScriptFailure(lines, 'E1202:') + v9.CheckSourceFailure(lines, 'E1202:') # Using an object without specifying a method or a member variable lines =<< trim END @@ -197,7 +197,7 @@ def Test_class_basic() var a = A.new() var v = a. END - v9.CheckScriptFailure(lines, 'E15:') + v9.CheckSourceFailure(lines, 'E15:') # Error when parsing the arguments of an object method. lines =<< trim END @@ -209,7 +209,7 @@ def Test_class_basic() var a = A.new() var v = a.Foo(,) END - v9.CheckScriptFailure(lines, 'E15:') + v9.CheckSourceFailure(lines, 'E15:') lines =<< trim END vim9script @@ -220,7 +220,7 @@ def Test_class_basic() endclass var a = A.new() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef def Test_class_defined_twice() @@ -232,7 +232,7 @@ def Test_class_defined_twice() class There endclass END - v9.CheckScriptFailure(lines, 'E1041: Redefining script item: "There"') + v9.CheckSourceFailure(lines, 'E1041: Redefining script item: "There"') # one class, reload same script twice is OK lines =<< trim END @@ -259,7 +259,7 @@ def Test_returning_null_object() var buffers = BufferList.new() echo buffers.Current() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef def Test_using_null_class() @@ -276,7 +276,7 @@ def Test_class_interface_wrong_end() this.member = 'text' endinterface END - v9.CheckScriptFailure(lines, 'E476: Invalid command: endinterface, expected endclass') + v9.CheckSourceFailure(lines, 'E476: Invalid command: endinterface, expected endclass') lines =<< trim END vim9script @@ -284,7 +284,7 @@ def Test_class_interface_wrong_end() this.member: string endclass END - v9.CheckScriptFailure(lines, 'E476: Invalid command: endclass, expected endinterface') + v9.CheckSourceFailure(lines, 'E476: Invalid command: endclass, expected endinterface') enddef def Test_object_not_set() @@ -299,7 +299,7 @@ def Test_object_not_set() var db = {'xyz': 789} echo db[state.value] END - v9.CheckScriptFailure(lines, 'E1360:') + v9.CheckSourceFailure(lines, 'E1360:') lines =<< trim END vim9script @@ -317,7 +317,7 @@ def Test_object_not_set() enddef Func() END - v9.CheckScriptFailure(lines, 'E1360:') + v9.CheckSourceFailure(lines, 'E1360:') lines =<< trim END vim9script @@ -337,7 +337,7 @@ def Test_object_not_set() var bg: Background # UNINITIALIZED echo Colorscheme.new(bg).GetBackground() END - v9.CheckScriptFailure(lines, 'E1360:') + v9.CheckSourceFailure(lines, 'E1360:') # TODO: this should not give an error but be handled at runtime lines =<< trim END @@ -356,7 +356,7 @@ def Test_object_not_set() enddef Func() END - v9.CheckScriptFailure(lines, 'E1363:') + v9.CheckSourceFailure(lines, 'E1363:') enddef def Test_null_object_assign_compare() @@ -396,7 +396,7 @@ def Test_null_object_assign_compare() o2 = null_object assert_true(o2 == null) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef def Test_class_member_initializer() @@ -432,7 +432,7 @@ def Test_class_member_initializer() '\d\+ RETURN object.*', instr) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef def Test_member_any_used_as_object() @@ -456,7 +456,7 @@ def Test_member_any_used_as_object() F(outer_obj) assert_equal(1, inner_obj.value) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -482,7 +482,51 @@ def Test_member_any_used_as_object() Test_assign_to_nested_typed_member() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) + + # Try modifying a private variable using an "any" object + lines =<< trim END + vim9script + + class Inner + this._value: string = '' + endclass + + class Outer + this.inner: any + endclass + + def F(outer: Outer) + outer.inner._value = 'b' + enddef + + var inner_obj = Inner.new('a') + var outer_obj = Outer.new(inner_obj) + F(outer_obj) + END + v9.CheckSourceFailure(lines, 'E1333: Cannot access private member: _value') + + # Try modifying a non-existing variable using an "any" object + lines =<< trim END + vim9script + + class Inner + this.value: string = '' + endclass + + class Outer + this.inner: any + endclass + + def F(outer: Outer) + outer.inner.someval = 'b' + enddef + + var inner_obj = Inner.new('a') + var outer_obj = Outer.new(inner_obj) + F(outer_obj) + END + v9.CheckSourceFailure(lines, 'E1326: Member not found on object "Inner": someval') enddef def Test_assignment_with_operator() @@ -508,7 +552,7 @@ def Test_assignment_with_operator() AddToFoo(f) assert_equal(23, f.x) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # do the same thing, but through an interface lines =<< trim END @@ -538,7 +582,7 @@ def Test_assignment_with_operator() AddToFoo(f) assert_equal(23, f.x) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef def Test_list_of_objects() @@ -559,7 +603,7 @@ def Test_list_of_objects() var l: list = [Foo.new()] ProcessList(l) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef def Test_expr_after_using_object() @@ -578,7 +622,7 @@ def Test_expr_after_using_object() Foo() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef def Test_class_default_new() @@ -606,7 +650,7 @@ def Test_class_default_new() assert_equal(1, pos.lnum) assert_equal(33, pos.col) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -629,7 +673,7 @@ def Test_class_default_new() assert_equal(4, chris.age) assert_equal("none", chris.education) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -644,7 +688,7 @@ def Test_class_default_new() var missing = Person.new() END - v9.CheckScriptFailure(lines, 'E119:') + v9.CheckSourceFailure(lines, 'E119:') enddef @@ -677,7 +721,7 @@ def Test_class_new_with_object_member() Check() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -699,7 +743,7 @@ def Test_class_new_with_object_member() Check() END - v9.CheckScriptFailure(lines, 'E1013:') + v9.CheckSourceFailure(lines, 'E1013:') lines =<< trim END vim9script @@ -721,7 +765,7 @@ def Test_class_new_with_object_member() Check() END - v9.CheckScriptFailure(lines, 'E1013:') + v9.CheckSourceFailure(lines, 'E1013:') enddef def Test_class_object_member_inits() @@ -738,7 +782,7 @@ def Test_class_object_member_inits() assert_equal(1, pos.col) assert_equal(2, pos.addcol) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -747,7 +791,7 @@ def Test_class_object_member_inits() this.col = 1 endclass END - v9.CheckScriptFailure(lines, 'E1022:') + v9.CheckSourceFailure(lines, 'E1022:') # If the type is not specified for a member, then it should be set during # object creation and not when defining the class. @@ -770,7 +814,7 @@ def Test_class_object_member_inits() var a = A.new() assert_equal(init_count, 2) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # Test for initializing an object member with an unknown variable/type lines =<< trim END @@ -780,10 +824,11 @@ def Test_class_object_member_inits() endclass var a = A.new() END - v9.CheckScriptFailure(lines, 'E1001:') + v9.CheckSourceFailure(lines, 'E1001:') enddef -def Test_class_object_member_access() +" Test for instance variable access +def Test_instance_variable_access() var lines =<< trim END vim9script class Triple @@ -807,9 +852,9 @@ def Test_class_object_member_access() trip.three = 33 assert_equal(33, trip.three) - assert_fails('trip.four = 4', 'E1334') + assert_fails('trip.four = 4', 'E1326') END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # Test for a public member variable name beginning with an underscore lines =<< trim END @@ -818,7 +863,7 @@ def Test_class_object_member_access() public this._val = 10 endclass END - v9.CheckScriptFailure(lines, 'E1332:') + v9.CheckSourceFailure(lines, 'E1332:') lines =<< trim END vim9script @@ -854,7 +899,7 @@ def Test_class_object_member_access() enddef CheckCar() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -870,7 +915,7 @@ def Test_class_object_member_access() var c = MyCar.new("abc") var c = MyCar.new("def") END - v9.CheckScriptFailure(lines, 'E1041:') + v9.CheckSourceFailure(lines, 'E1041:') lines =<< trim END vim9script @@ -896,7 +941,7 @@ def Test_class_object_member_access() .Add(2) .x END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # Test for "public" cannot be abbreviated lines =<< trim END @@ -905,7 +950,7 @@ def Test_class_object_member_access() pub this.val = 1 endclass END - v9.CheckScriptFailure(lines, 'E1065:') + v9.CheckSourceFailure(lines, 'E1065:') # Test for "public" keyword must be followed by "this" or "static". lines =<< trim END @@ -914,25 +959,53 @@ def Test_class_object_member_access() public val = 1 endclass END - v9.CheckScriptFailure(lines, 'E1331:') + v9.CheckSourceFailure(lines, 'E1331:') - # Test for "static" cannot be abbreviated + # Modify a instance variable using the class name in the script context lines =<< trim END vim9script - class Something - stat this.val = 1 + class A + public this.val = 1 endclass + A.val = 1 END - v9.CheckScriptFailure(lines, 'E1065:') + v9.CheckSourceFailure(lines, 'E1376: Object member "val" accessible only using class "A" object') - # Test for "static" cannot be followed by "this". + # Read a instance variable using the class name in the script context lines =<< trim END vim9script - class Something - static this.val = 1 + class A + public this.val = 1 endclass + var i = A.val END - v9.CheckScriptFailure(lines, 'E1368: Static cannot be followed by "this" in a member name') + v9.CheckSourceFailure(lines, 'E1376: Object member "val" accessible only using class "A" object') + + # Modify a instance variable using the class name in a def function + lines =<< trim END + vim9script + class A + public this.val = 1 + endclass + def T() + A.val = 1 + enddef + T() + END + v9.CheckSourceFailure(lines, 'E1376: Object member "val" accessible only using class "A" object') + + # Read a instance variable using the class name in a def function + lines =<< trim END + vim9script + class A + public this.val = 1 + endclass + def T() + var i = A.val + enddef + T() + END + v9.CheckSourceFailure(lines, 'E1376: Object member "val" accessible only using class "A" object') # Access from child class extending a class: lines =<< trim END @@ -941,10 +1014,6 @@ def Test_class_object_member_access() this.ro_obj_var = 10 public this.rw_obj_var = 20 this._priv_obj_var = 30 - - static ro_class_var = 40 - public static rw_class_var = 50 - static _priv_class_var = 60 endclass class B extends A @@ -956,19 +1025,89 @@ def Test_class_object_member_access() this.rw_obj_var = 0 x = this._priv_obj_var this._priv_obj_var = 0 + enddef + endclass - x = ro_class_var - ro_class_var = 0 - x = rw_class_var - rw_class_var = 0 - x = _priv_class_var - _priv_class_var = 0 + var b = B.new() + b.Foo() + END + v9.CheckSourceSuccess(lines) +enddef - x = A.ro_class_var - A.ro_class_var = 0 - x = A.rw_class_var - A.rw_class_var = 0 - x = A._priv_class_var +" Test for class variable access +def Test_class_variable_access() + # Test for "static" cannot be abbreviated + var lines =<< trim END + vim9script + class Something + stat this.val = 1 + endclass + END + v9.CheckSourceFailure(lines, 'E1065:') + + # Test for "static" cannot be followed by "this". + lines =<< trim END + vim9script + class Something + static this.val = 1 + endclass + END + v9.CheckSourceFailure(lines, 'E1368: Static cannot be followed by "this" in a member name') + + # Test for "static" cannot be followed by "public". + lines =<< trim END + vim9script + class Something + static public val = 1 + endclass + END + v9.CheckSourceFailure(lines, 'E1022: Type or initialization required') + + # A readonly class variable cannot be modified from a child class + lines =<< trim END + vim9script + class A + static ro_class_var = 40 + endclass + + class B extends A + def Foo() + A.ro_class_var = 50 + enddef + endclass + + var b = B.new() + b.Foo() + END + v9.CheckSourceFailure(lines, 'E46: Cannot change read-only variable "ro_class_var"') + + # A private class variable cannot be accessed from a child class + lines =<< trim END + vim9script + class A + static _priv_class_var = 60 + endclass + + class B extends A + def Foo() + var i = A._priv_class_var + enddef + endclass + + var b = B.new() + b.Foo() + END + v9.CheckSourceFailure(lines, 'E1333: Cannot access private member: _priv_class_var') + + # A private class variable cannot be modified from a child class + lines =<< trim END + vim9script + class A + static _priv_class_var = 60 + endclass + + class B extends A + def Foo() A._priv_class_var = 0 enddef endclass @@ -976,7 +1115,37 @@ def Test_class_object_member_access() var b = B.new() b.Foo() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceFailure(lines, 'E1333: Cannot access private member: _priv_class_var') + + # Access from child class extending a class and from script context + lines =<< trim END + vim9script + class A + static ro_class_var = 10 + public static rw_class_var = 20 + static _priv_class_var = 30 + endclass + + class B extends A + def Foo() + var x: number + x = A.ro_class_var + assert_equal(10, x) + x = A.rw_class_var + assert_equal(25, x) + A.rw_class_var = 20 + assert_equal(20, A.rw_class_var) + enddef + endclass + + assert_equal(10, A.ro_class_var) + assert_equal(20, A.rw_class_var) + A.rw_class_var = 25 + assert_equal(25, A.rw_class_var) + var b = B.new() + b.Foo() + END + v9.CheckSourceSuccess(lines) enddef def Test_class_object_compare() @@ -1005,8 +1174,8 @@ def Test_class_object_compare() assert_notequal(i1, io2) END - v9.CheckScriptSuccess(class_lines + test_lines) - v9.CheckScriptSuccess( + v9.CheckSourceSuccess(class_lines + test_lines) + v9.CheckSourceSuccess( class_lines + ['def Test()'] + test_lines + ['enddef', 'Test()']) for op in ['>', '>=', '<', '<=', '=~', '!~'] @@ -1015,8 +1184,8 @@ def Test_class_object_compare() 'var i2 = Item.new()', 'echo i1 ' .. op .. ' i2', ] - v9.CheckScriptFailure(class_lines + op_lines, 'E1153: Invalid operation for object') - v9.CheckScriptFailure(class_lines + v9.CheckSourceFailure(class_lines + op_lines, 'E1153: Invalid operation for object') + v9.CheckSourceFailure(class_lines + ['def Test()'] + op_lines + ['enddef', 'Test()'], 'E1153: Invalid operation for object') endfor enddef @@ -1042,7 +1211,7 @@ def Test_object_type() t = m END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -1056,7 +1225,7 @@ def Test_object_type() var o: One = Two.new() END - v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected object but got object') + v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected object but got object') lines =<< trim END vim9script @@ -1074,7 +1243,7 @@ def Test_object_type() var o: One = Two.new(5) assert_equal(5, o.GetMember()) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -1094,7 +1263,7 @@ def Test_object_type() echo Fn(Num.new(4)) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef def Test_class_member() @@ -1116,7 +1285,7 @@ def Test_class_member() assert_equal(0, TextPos.counter) TextPos.AddToCounter(3) assert_equal(3, TextPos.counter) - assert_fails('echo TextPos.noSuchMember', 'E1338:') + assert_fails('echo TextPos.noSuchMember', 'E1337:') def GetCounter(): number return TextPos.counter @@ -1136,7 +1305,7 @@ def Test_class_member() TextPos.anybody += 5 assert_equal(17, TextPos.anybody) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # example in the help lines =<< trim END @@ -1155,7 +1324,7 @@ def Test_class_member() var to7 = OtherThing.new(7) assert_equal(10, OtherThing.totalSize) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # using static class member twice lines =<< trim END @@ -1172,7 +1341,7 @@ def Test_class_member() assert_equal('some text', HTML.MacroSubstitute('some text')) assert_equal('some text', HTML.MacroSubstitute('some text')) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # access private member in lambda lines =<< trim END @@ -1190,7 +1359,7 @@ def Test_class_member() var foo = Foo.new() assert_equal(5, foo.Add(5)) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # access private member in lambda body lines =<< trim END @@ -1211,7 +1380,7 @@ def Test_class_member() var foo = Foo.new() assert_equal(13, foo.Add(7)) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # check shadowing lines =<< trim END @@ -1227,7 +1396,7 @@ def Test_class_member() var s = Some.new() s.Method(7) END - v9.CheckScriptFailure(lines, 'E1340: Argument already declared in the class: count') + v9.CheckSourceFailure(lines, 'E1340: Argument already declared in the class: count') lines =<< trim END vim9script @@ -1243,7 +1412,7 @@ def Test_class_member() var s = Some.new() s.Method(7) END - v9.CheckScriptFailure(lines, 'E1341: Variable already declared in the class: count') + v9.CheckSourceFailure(lines, 'E1341: Variable already declared in the class: count') # Test for using an invalid type for a member variable lines =<< trim END @@ -1252,7 +1421,7 @@ def Test_class_member() this.val: xxx endclass END - v9.CheckScriptFailure(lines, 'E1010:') + v9.CheckSourceFailure(lines, 'E1010:') # Test for setting a member on a null object lines =<< trim END @@ -1267,7 +1436,7 @@ def Test_class_member() enddef F() END - v9.CheckScriptFailure(lines, 'E1360: Using a null object') + v9.CheckSourceFailure(lines, 'E1360: Using a null object') # Test for accessing a member on a null object lines =<< trim END @@ -1282,7 +1451,7 @@ def Test_class_member() enddef F() END - v9.CheckScriptFailure(lines, 'E1360: Using a null object') + v9.CheckSourceFailure(lines, 'E1360: Using a null object') # Test for setting a member on a null object, at script level lines =<< trim END @@ -1295,7 +1464,7 @@ def Test_class_member() obj.val = "" END # FIXME(in source): this should give E1360 as well! - v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected object but got string') + v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected object but got string') # Test for accessing a member on a null object, at script level lines =<< trim END @@ -1307,7 +1476,7 @@ def Test_class_member() var obj: A echo obj.val END - v9.CheckScriptFailure(lines, 'E1360: Using a null object') + v9.CheckSourceFailure(lines, 'E1360: Using a null object') # Test for no space before or after the '=' when initializing a member # variable @@ -1317,14 +1486,14 @@ def Test_class_member() this.val: number= 10 endclass END - v9.CheckScriptFailure(lines, 'E1004:') + v9.CheckSourceFailure(lines, 'E1004:') lines =<< trim END vim9script class A this.val: number =10 endclass END - v9.CheckScriptFailure(lines, 'E1004:') + v9.CheckSourceFailure(lines, 'E1004:') # Access a non-existing member lines =<< trim END @@ -1334,7 +1503,7 @@ def Test_class_member() var a = A.new() var v = a.bar END - v9.CheckScriptFailure(lines, 'E1326:') + v9.CheckSourceFailure(lines, 'E1326: Member not found on object "A": bar') enddef func Test_class_garbagecollect() @@ -1351,7 +1520,7 @@ func Test_class_garbagecollect() call test_garbagecollect_now() echo Point.pl Point.pd END - call v9.CheckScriptSuccess(lines) + call v9.CheckSourceSuccess(lines) let lines =<< trim END vim9script @@ -1378,7 +1547,7 @@ func Test_class_garbagecollect() view = MyView.new() test_garbagecollect_now() END - call v9.CheckScriptSuccess(lines) + call v9.CheckSourceSuccess(lines) endfunc " Test interface garbage collection @@ -1432,7 +1601,7 @@ func Test_interface_garbagecollect() assert_equal(60, A.ClassFoo()) assert_equal(150, o.ObjFoo()) END - call v9.CheckScriptSuccess(lines) + call v9.CheckSourceSuccess(lines) endfunc def Test_class_function() @@ -1458,7 +1627,7 @@ def Test_class_function() var v2 = Value.new(7) assert_equal(2, Value.GetCount()) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # Test for cleaning up after a class definition failure when using class # functions. @@ -1470,7 +1639,7 @@ def Test_class_function() aaa endclass END - v9.CheckScriptFailure(lines, 'E1318:') + v9.CheckSourceFailure(lines, 'E1318:') enddef def Test_class_defcompile() @@ -1485,7 +1654,7 @@ def Test_class_defcompile() defcompile C.Fo END - v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got number') + v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected string but got number') lines =<< trim END vim9script @@ -1498,7 +1667,7 @@ def Test_class_defcompile() defcompile C.Fc END - v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected number but got string') + v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected number but got string') lines =<< trim END vim9script @@ -1510,14 +1679,14 @@ def Test_class_defcompile() defcompile C.new END - v9.CheckScriptFailure(lines, 'E1370: Cannot define a "new" function as static') + v9.CheckSourceFailure(lines, 'E1370: Cannot define a "new" function as static') # Trying to compile a function using a non-existing class variable lines =<< trim END vim9script defcompile x.Foo() END - v9.CheckScriptFailure(lines, 'E475:') + v9.CheckSourceFailure(lines, 'E475:') # Trying to compile a function using a variable which is not a class lines =<< trim END @@ -1525,7 +1694,7 @@ def Test_class_defcompile() var x: number defcompile x.Foo() END - v9.CheckScriptFailure(lines, 'E475:') + v9.CheckSourceFailure(lines, 'E475:') # Trying to compile a function without specifying the name lines =<< trim END @@ -1534,7 +1703,7 @@ def Test_class_defcompile() endclass defcompile A. END - v9.CheckScriptFailure(lines, 'E475:') + v9.CheckSourceFailure(lines, 'E475:') # Trying to compile a non-existing class object member function lines =<< trim END @@ -1544,7 +1713,7 @@ def Test_class_defcompile() var a = A.new() defcompile a.Foo() END - v9.CheckScriptFailureList(lines, ['E1334:', 'E475:']) + v9.CheckSourceFailureList(lines, ['E1326:', 'E475:']) enddef def Test_class_object_to_string() @@ -1560,7 +1729,7 @@ def Test_class_object_to_string() var pos = TextPosition.new() assert_equal("object of TextPosition {lnum: 1, col: 22}", string(pos)) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef def Test_interface_basics() @@ -1572,14 +1741,14 @@ def Test_interface_basics() def GetCount(): number endinterface END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END interface SomethingWrong static count = 7 endinterface END - v9.CheckScriptFailure(lines, 'E1342:') + v9.CheckSourceFailure(lines, 'E1342:') lines =<< trim END vim9script @@ -1589,7 +1758,7 @@ def Test_interface_basics() def Method(count: number) endinterface END - v9.CheckScriptFailure(lines, 'E1340: Argument already declared in the class: count', 5) + v9.CheckSourceFailure(lines, 'E1340: Argument already declared in the class: count', 5) lines =<< trim END vim9script @@ -1601,7 +1770,7 @@ def Test_interface_basics() END # The argument name and the object member name are the same, but this is not a # problem because object members are always accessed with the "this." prefix. - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -1609,7 +1778,7 @@ def Test_interface_basics() static count = 7 endinterface END - v9.CheckScriptFailure(lines, 'E1343: Interface name must start with an uppercase letter: somethingWrong') + v9.CheckSourceFailure(lines, 'E1343: Interface name must start with an uppercase letter: somethingWrong') lines =<< trim END vim9script @@ -1619,7 +1788,7 @@ def Test_interface_basics() def GetCount(): number endinterface END - v9.CheckScriptFailure(lines, 'E1344:') + v9.CheckSourceFailure(lines, 'E1344:') lines =<< trim END vim9script @@ -1631,7 +1800,7 @@ def Test_interface_basics() enddef endinterface END - v9.CheckScriptFailure(lines, 'E1345: Not a valid command in an interface: return 5') + v9.CheckSourceFailure(lines, 'E1345: Not a valid command in an interface: return 5') lines =<< trim END vim9script @@ -1699,7 +1868,7 @@ def Test_class_implements_interface() enddef endclass END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -1712,7 +1881,7 @@ def Test_class_implements_interface() static count: number endclass END - v9.CheckScriptFailure(lines, 'E1350:') + v9.CheckSourceFailure(lines, 'E1350:') lines =<< trim END vim9script @@ -1725,7 +1894,7 @@ def Test_class_implements_interface() static count: number endclass END - v9.CheckScriptFailure(lines, 'E1351: Duplicate interface after "implements": Some') + v9.CheckSourceFailure(lines, 'E1351: Duplicate interface after "implements": Some') lines =<< trim END vim9script @@ -1742,7 +1911,7 @@ def Test_class_implements_interface() enddef endclass END - v9.CheckScriptFailure(lines, 'E1348: Member "counter" of interface "Some" not implemented') + v9.CheckSourceFailure(lines, 'E1348: Member "counter" of interface "Some" not implemented') lines =<< trim END vim9script @@ -1759,7 +1928,7 @@ def Test_class_implements_interface() enddef endclass END - v9.CheckScriptFailure(lines, 'E1349: Function "Methods" of interface "Some" not implemented') + v9.CheckSourceFailure(lines, 'E1349: Function "Methods" of interface "Some" not implemented') # Check different order of members in class and interface works. lines =<< trim END @@ -1789,7 +1958,7 @@ def Test_class_implements_interface() Test() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # Interface name after "extends" doesn't end in a space or NUL character lines =<< trim END @@ -1799,7 +1968,7 @@ def Test_class_implements_interface() class B extends A" endclass END - v9.CheckScriptFailure(lines, 'E1315:') + v9.CheckSourceFailure(lines, 'E1315:') # Trailing characters after a class name lines =<< trim END @@ -1807,7 +1976,7 @@ def Test_class_implements_interface() class A bbb endclass END - v9.CheckScriptFailure(lines, 'E488:') + v9.CheckSourceFailure(lines, 'E488:') # using "implements" with a non-existing class lines =<< trim END @@ -1815,7 +1984,7 @@ def Test_class_implements_interface() class A implements B endclass END - v9.CheckScriptFailure(lines, 'E1346:') + v9.CheckSourceFailure(lines, 'E1346:') # using "implements" with a regular class lines =<< trim END @@ -1825,7 +1994,7 @@ def Test_class_implements_interface() class B implements A endclass END - v9.CheckScriptFailure(lines, 'E1347:') + v9.CheckSourceFailure(lines, 'E1347:') # using "implements" with a variable lines =<< trim END @@ -1834,7 +2003,7 @@ def Test_class_implements_interface() class A implements T endclass END - v9.CheckScriptFailure(lines, 'E1347:') + v9.CheckSourceFailure(lines, 'E1347:') # all the class methods in an "interface" should be implemented lines =<< trim END @@ -1845,7 +2014,7 @@ def Test_class_implements_interface() class B implements A endclass END - v9.CheckScriptFailure(lines, 'E1349:') + v9.CheckSourceFailure(lines, 'E1349:') # implements should be followed by a white space lines =<< trim END @@ -1855,7 +2024,7 @@ def Test_class_implements_interface() class B implements A; endclass END - v9.CheckScriptFailure(lines, 'E1315:') + v9.CheckSourceFailure(lines, 'E1315:') lines =<< trim END vim9script @@ -1871,7 +2040,7 @@ def Test_class_implements_interface() static matching: bool endclass END - v9.CheckScriptFailure(lines, 'E1406: Member "not_matching": type mismatch, expected number but got string') + v9.CheckSourceFailure(lines, 'E1406: Member "not_matching": type mismatch, expected number but got string') lines =<< trim END vim9script @@ -1884,7 +2053,7 @@ def Test_class_implements_interface() enddef endclass END - v9.CheckScriptFailure(lines, 'E1407: Method "IsEven": type mismatch, expected func(number): bool but got func(number): string') + v9.CheckSourceFailure(lines, 'E1407: Method "IsEven": type mismatch, expected func(number): bool but got func(number): string') lines =<< trim END vim9script @@ -1897,7 +2066,7 @@ def Test_class_implements_interface() enddef endclass END - v9.CheckScriptFailure(lines, 'E1407: Method "IsEven": type mismatch, expected func(number): bool but got func(bool): bool') + v9.CheckSourceFailure(lines, 'E1407: Method "IsEven": type mismatch, expected func(number): bool but got func(bool): bool') lines =<< trim END vim9script @@ -1910,7 +2079,7 @@ def Test_class_implements_interface() enddef endclass END - v9.CheckScriptFailure(lines, 'E1407: Method "IsEven": type mismatch, expected func(number): bool but got func(number, ...list): bool') + v9.CheckSourceFailure(lines, 'E1407: Method "IsEven": type mismatch, expected func(number): bool but got func(number, ...list): bool') # access superclass interface members from subclass, mix variable order lines =<< trim END @@ -1939,8 +2108,6 @@ def Test_class_implements_interface() class B extends A def new() - svar1 = 21 - svar2 = 22 this.mvar1 = 121 this.mvar2 = 122 enddef @@ -1948,8 +2115,6 @@ def Test_class_implements_interface() class C extends B def new() - svar1 = 31 - svar2 = 32 this.mvar1 = 131 this.mvar2 = 132 enddef @@ -1967,7 +2132,7 @@ def Test_class_implements_interface() assert_equal([121, 122], F2(ob)) assert_equal([131, 132], F2(oc)) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # Access superclass interface members from subclass, mix variable order. # Two interfaces, one on A, one on B; each has both kinds of variables @@ -2007,8 +2172,6 @@ def Test_class_implements_interface() public this.mvar3: number public this.mvar4: number def new() - svar1 = 21 - svar2 = 22 svar3 = 23 svar4 = 24 this.mvar1 = 121 @@ -2021,10 +2184,6 @@ def Test_class_implements_interface() class C extends B public static svar5: number def new() - svar1 = 31 - svar2 = 32 - svar3 = 33 - svar4 = 34 svar5 = 1001 this.mvar1 = 131 this.mvar2 = 132 @@ -2049,7 +2208,7 @@ def Test_class_implements_interface() assert_equal([[121, 122], [123, 124]], [F2(ob), F4(ob)]) assert_equal([[131, 132], [133, 134]], [F2(oc), F4(oc)]) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef def Test_call_interface_method() @@ -2074,7 +2233,7 @@ def Test_call_interface_method() assert_equal('child', g:result) unlet g:result END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -2099,7 +2258,7 @@ def Test_call_interface_method() assert_equal('child', g:result) unlet g:result END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # method of interface returns a value lines =<< trim END @@ -2125,7 +2284,7 @@ def Test_call_interface_method() assert_equal('child/resource', g:result) unlet g:result END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -2152,7 +2311,7 @@ def Test_call_interface_method() assert_equal('child/resource', g:result) unlet g:result END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # No class that implements the interface. @@ -2170,7 +2329,7 @@ def Test_call_interface_method() defcompile END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef def Test_class_used_as_type() @@ -2187,7 +2346,7 @@ def Test_class_used_as_type() assert_equal(2, p.x) assert_equal(33, p.y) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -2206,7 +2365,7 @@ def Test_class_used_as_type() var hx = p assert_equal(2, hx.x) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -2219,7 +2378,7 @@ def Test_class_used_as_type() var p: Point p = 'text' END - v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected object but got string') + v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected object but got string') enddef def Test_class_extends() @@ -2243,7 +2402,7 @@ def Test_class_extends() assert_equal(1, o.GetOne()) assert_equal(3, o.GetTotal()) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -2257,7 +2416,7 @@ def Test_class_extends() assert_equal(3, o.one) assert_equal(44, o.two) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -2268,7 +2427,7 @@ def Test_class_extends() this.two = 2 endclass END - v9.CheckScriptFailure(lines, 'E1352: Duplicate "extends"') + v9.CheckSourceFailure(lines, 'E1352: Duplicate "extends"') lines =<< trim END vim9script @@ -2276,7 +2435,7 @@ def Test_class_extends() this.two = 2 endclass END - v9.CheckScriptFailure(lines, 'E1353: Class name not found: BaseClass') + v9.CheckSourceFailure(lines, 'E1353: Class name not found: BaseClass') lines =<< trim END vim9script @@ -2285,7 +2444,7 @@ def Test_class_extends() this.two = 2 endclass END - v9.CheckScriptFailure(lines, 'E1354: Cannot extend SomeVar') + v9.CheckSourceFailure(lines, 'E1354: Cannot extend SomeVar') lines =<< trim END vim9script @@ -2306,7 +2465,7 @@ def Test_class_extends() var o = Child.new('John', 42) assert_equal('John: 42', o.ToString()) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -2320,7 +2479,7 @@ def Test_class_extends() enddef endclass END - v9.CheckScriptFailure(lines, 'E1355: Duplicate function: ToString') + v9.CheckSourceFailure(lines, 'E1355: Duplicate function: ToString') lines =<< trim END vim9script @@ -2333,7 +2492,7 @@ def Test_class_extends() var o = Child.new(42) echo o.ToString() END - v9.CheckScriptFailure(lines, 'E1356:') + v9.CheckSourceFailure(lines, 'E1356:') lines =<< trim END vim9script @@ -2350,7 +2509,7 @@ def Test_class_extends() enddef echo ToString() END - v9.CheckScriptFailure(lines, 'E1357:') + v9.CheckSourceFailure(lines, 'E1357:') lines =<< trim END vim9script @@ -2363,7 +2522,7 @@ def Test_class_extends() var o = Child.new(42) echo o.ToString() END - v9.CheckScriptFailure(lines, 'E1358:') + v9.CheckSourceFailure(lines, 'E1358:') lines =<< trim END vim9script @@ -2384,7 +2543,7 @@ def Test_class_extends() var o = Child.new('John', 42) assert_equal('Base class: 42', o.ToString()) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -2401,7 +2560,7 @@ def Test_class_extends() endclass var c = Child.new() END - v9.CheckScriptFailure(lines, 'E1325: Method not found on class "Child": new(') + v9.CheckSourceFailure(lines, 'E1375: Class member "new" accessible only using class "Child"') # base class with more than one object member lines =<< trim END @@ -2421,7 +2580,7 @@ def Test_class_extends() var v = Success.new('asdf') assert_equal("object of Success {success: true, value: 'asdf'}", string(v)) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # class name after "extends" doesn't end in a space or NUL character lines =<< trim END @@ -2431,7 +2590,7 @@ def Test_class_extends() class B extends A" endclass END - v9.CheckScriptFailure(lines, 'E1315:') + v9.CheckSourceFailure(lines, 'E1315:') enddef def Test_using_base_class() @@ -2470,7 +2629,7 @@ def Test_using_base_class() With(ChildEE.new()) assert_equal('42/finally/exit', g:result) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) unlet g:result # Using super, Child invokes Base method which has optional arg. #12471 @@ -2493,7 +2652,7 @@ def Test_using_base_class() var obj = Child.new() assert_equal(true, obj.success) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef @@ -2536,7 +2695,7 @@ def Test_abstract_class() assert_equal('Peter', p.name) assert_equal(42, p.age) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -2548,14 +2707,14 @@ def Test_abstract_class() endclass var p = Base.new('Peter') END - v9.CheckScriptFailure(lines, 'E1325: Method not found on class "Base": new(') + v9.CheckSourceFailure(lines, 'E1325: Method not found on class "Base": new') lines =<< trim END abstract class Base this.name: string endclass END - v9.CheckScriptFailure(lines, 'E1316:') + v9.CheckSourceFailure(lines, 'E1316:') # Abstract class cannot have a "new" function lines =<< trim END @@ -2565,7 +2724,7 @@ def Test_abstract_class() enddef endclass END - v9.CheckScriptFailure(lines, 'E1359:') + v9.CheckSourceFailure(lines, 'E1359:') enddef def Test_closure_in_class() @@ -2583,7 +2742,7 @@ def Test_closure_in_class() Foo.new() assert_equal(['A'], g:result) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef def Test_call_constructor_from_legacy() @@ -2606,7 +2765,7 @@ def Test_call_constructor_from_legacy() legacy call p.new() assert_equal('true', newCalled) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef def Test_defer_with_object() @@ -2635,7 +2794,7 @@ def Test_defer_with_object() }) assert_equal('entered/called/exited', g:result) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) unlet g:result lines =<< trim END @@ -2672,7 +2831,7 @@ def Test_defer_with_object() }) assert_equal('entered-child/called/exited-child', g:result) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) unlet g:result enddef @@ -2712,7 +2871,7 @@ def Test_extends_method_crashes_vim() p.Set(true) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef " Test for calling a method in a class that is extended @@ -2747,7 +2906,7 @@ def Test_call_method_in_extended_class() assert_true(prop_init_called) assert_true(prop_register_called) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef def Test_instanceof() @@ -2794,7 +2953,7 @@ def Test_instanceof() enddef Foo() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef " Test for calling a method in the parent class that is extended partially. @@ -2832,7 +2991,7 @@ def Test_call_method_in_parent_class() var foo2 = Foo.new() var l = Stack(foo1, foo2) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef " Test for calling methods from three levels of classes @@ -2906,7 +3065,7 @@ def Test_multi_level_method_call() assert_equal(0, B_func3) assert_equal(3, C_func3) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef " Test for using members from three levels of classes @@ -2949,7 +3108,7 @@ def Test_multi_level_member_access() assert_equal(2, cobj.val2) assert_equal(1, cobj.val3) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef " Test expansion of with class methods. @@ -2973,7 +3132,7 @@ def Test_stack_expansion_with_methods() F() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef " Test the return type of the new() constructor @@ -3006,7 +3165,7 @@ def Test_new_return_type() enddef F() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # new() uses the default return type and an empty 'return' statement lines =<< trim END @@ -3037,7 +3196,7 @@ def Test_new_return_type() enddef F() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # new() uses "any" return type and returns "this" lines =<< trim END @@ -3054,7 +3213,7 @@ def Test_new_return_type() enddef endclass END - v9.CheckScriptFailure(lines, 'E1365:') + v9.CheckSourceFailure(lines, 'E1365:') # new() uses 'Dict' return type and returns a Dict lines =<< trim END @@ -3072,7 +3231,7 @@ def Test_new_return_type() var c = C.new() assert_equal('object', typename(c)) END - v9.CheckScriptFailure(lines, 'E1365:') + v9.CheckSourceFailure(lines, 'E1365:') enddef " Test for checking a member initialization type at run time. @@ -3098,7 +3257,7 @@ def Test_runtime_type_check_for_member_init() var c1 = C.new() var c2 = C.new() END - v9.CheckScriptFailure(lines, 'E1012:') + v9.CheckSourceFailure(lines, 'E1012:') enddef " Test for locking a variable referring to an object and reassigning to another @@ -3135,7 +3294,7 @@ def Test_object_lockvar() G() assert_equal(2, current.val) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef " Test for a private object method @@ -3152,7 +3311,7 @@ def Test_private_object_method() var a = A.new() a._Foo() END - v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()') + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()') # Try calling a private method using an object (from a def function) lines =<< trim END @@ -3169,7 +3328,7 @@ def Test_private_object_method() enddef T() END - v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()') + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()') # Use a private method from another object method (in script context) lines =<< trim END @@ -3186,7 +3345,7 @@ def Test_private_object_method() var a = A.new() assert_equal(1234, a.Bar()) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # Use a private method from another object method (def function context) lines =<< trim END @@ -3206,7 +3365,7 @@ def Test_private_object_method() enddef T() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # Try calling a private method without the "this" prefix lines =<< trim END @@ -3223,7 +3382,7 @@ def Test_private_object_method() var a = A.new() a.Bar() END - v9.CheckScriptFailure(lines, 'E117: Unknown function: _Foo') + v9.CheckSourceFailure(lines, 'E117: Unknown function: _Foo') # Try calling a private method using the class name lines =<< trim END @@ -3236,7 +3395,7 @@ def Test_private_object_method() endclass A._Foo() END - v9.CheckScriptFailure(lines, 'E1325: Method not found on class "A": _Foo()') + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo') # Try to use "public" keyword when defining a private method lines =<< trim END @@ -3249,7 +3408,7 @@ def Test_private_object_method() var a = A.new() a._Foo() END - v9.CheckScriptFailure(lines, 'E1331: Public must be followed by "this" or "static"') + v9.CheckSourceFailure(lines, 'E1331: Public must be followed by "this" or "static"') # Define two private methods with the same name lines =<< trim END @@ -3263,7 +3422,7 @@ def Test_private_object_method() endclass var a = A.new() END - v9.CheckScriptFailure(lines, 'E1355: Duplicate function: _Foo') + v9.CheckSourceFailure(lines, 'E1355: Duplicate function: _Foo') # Define a private method and a object method with the same name lines =<< trim END @@ -3277,7 +3436,7 @@ def Test_private_object_method() endclass var a = A.new() END - v9.CheckScriptFailure(lines, 'E1355: Duplicate function: Foo') + v9.CheckSourceFailure(lines, 'E1355: Duplicate function: Foo') # Define an object method and a private method with the same name lines =<< trim END @@ -3291,7 +3450,7 @@ def Test_private_object_method() endclass var a = A.new() END - v9.CheckScriptFailure(lines, 'E1355: Duplicate function: _Foo') + v9.CheckSourceFailure(lines, 'E1355: Duplicate function: _Foo') # Call a public method and a private method from a private method lines =<< trim END @@ -3315,7 +3474,7 @@ def Test_private_object_method() var a = A.new() a.T() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # Try calling a private method from another class lines =<< trim END @@ -3335,7 +3494,7 @@ def Test_private_object_method() var b = B.new() b.Foo() END - v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()') + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()') # Call a private object method from a child class object method lines =<< trim END @@ -3357,7 +3516,7 @@ def Test_private_object_method() var c = C.new() assert_equal(1234, c.Baz()) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # Call a private object method from a child class object lines =<< trim END @@ -3378,7 +3537,7 @@ def Test_private_object_method() var c = C.new() assert_equal(1234, c._Foo()) END - v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()') + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()') # Using "_" prefix in a method name should fail outside of a class lines =<< trim END @@ -3388,7 +3547,7 @@ def Test_private_object_method() enddef var a = _Foo() END - v9.CheckScriptFailure(lines, 'E1267: Function name must start with a capital: _Foo(): number') + v9.CheckSourceFailure(lines, 'E1267: Function name must start with a capital: _Foo(): number') enddef " Test for an private class method @@ -3404,7 +3563,7 @@ def Test_private_class_method() endclass A._Foo() END - v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()') + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()') # Try calling a class private method (from a def function) lines =<< trim END @@ -3420,7 +3579,7 @@ def Test_private_class_method() enddef T() END - v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()') + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()') # Try calling a class private method using an object (at the script level) lines =<< trim END @@ -3434,7 +3593,7 @@ def Test_private_class_method() var a = A.new() a._Foo() END - v9.CheckScriptFailure(lines, 'E1325: Method not found on class "A": _Foo()') + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo') # Try calling a class private method using an object (from a def function) lines =<< trim END @@ -3451,7 +3610,7 @@ def Test_private_class_method() enddef T() END - v9.CheckScriptFailure(lines, 'E1325: Method not found on class "A": _Foo()') + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo') # Use a class private method from an object method lines =<< trim END @@ -3468,7 +3627,7 @@ def Test_private_class_method() var a = A.new() a.Bar() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # Use a class private method from another class private method lines =<< trim END @@ -3488,7 +3647,7 @@ def Test_private_class_method() var a = A.new() a.Bar() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # Declare a class method and a class private method with the same name lines =<< trim END @@ -3502,7 +3661,7 @@ def Test_private_class_method() endclass var a = A.new() END - v9.CheckScriptFailure(lines, 'E1355: Duplicate function: Foo') + v9.CheckSourceFailure(lines, 'E1355: Duplicate function: Foo') # Try calling a class private method from another class lines =<< trim END @@ -3521,7 +3680,7 @@ def Test_private_class_method() var b = B.new() assert_equal(1234, b.Foo()) END - v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()') + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()') # Call a private class method from a child class object method lines =<< trim END @@ -3543,7 +3702,7 @@ def Test_private_class_method() var c = C.new() assert_equal(1234, c.Baz()) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()') # Call a private class method from a child class private class method lines =<< trim END @@ -3564,7 +3723,7 @@ def Test_private_class_method() endclass assert_equal(1234, C.Baz()) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()') # Call a private class method from a child class object lines =<< trim END @@ -3585,7 +3744,7 @@ def Test_private_class_method() var c = C.new() assert_equal(1234, C._Foo()) END - v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()') + v9.CheckSourceFailure(lines, 'E1325: Method not found on class "C": _Foo') enddef " Test for an interface private object_method @@ -3607,7 +3766,7 @@ def Test_interface_private_object_method() var a = A.new() assert_equal(1234, a.Bar()) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # Call an interface private class method (script context) lines =<< trim END @@ -3623,7 +3782,7 @@ def Test_interface_private_object_method() var a = A.new() assert_equal(1234, a._Foo()) END - v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()') + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()') # Call an interface private class method (def context) lines =<< trim END @@ -3642,7 +3801,7 @@ def Test_interface_private_object_method() enddef T() END - v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo()') + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()') # Implement an interface private object method as a private class method lines =<< trim END @@ -3656,7 +3815,7 @@ def Test_interface_private_object_method() enddef endclass END - v9.CheckScriptFailure(lines, 'E1349: Function "_Foo" of interface "Intf" not implemented') + v9.CheckSourceFailure(lines, 'E1349: Function "_Foo" of interface "Intf" not implemented') enddef " Test for an interface private class method @@ -3678,7 +3837,7 @@ def Test_interface_private_class_method() var a = A.new() assert_equal(1234, a.Bar()) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # Call an interface private class method (script context) lines =<< trim END @@ -3693,7 +3852,7 @@ def Test_interface_private_class_method() endclass assert_equal(1234, A._Foo()) END - v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo())') + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo())') # Call an interface private class method (def context) lines =<< trim END @@ -3711,7 +3870,7 @@ def Test_interface_private_class_method() enddef T() END - v9.CheckScriptFailure(lines, 'E1366: Cannot access private method: _Foo())') + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo())') # Implement an interface private class method as a private object method lines =<< trim END @@ -3725,7 +3884,7 @@ def Test_interface_private_class_method() enddef endclass END - v9.CheckScriptFailure(lines, 'E1349: Function "_Foo" of interface "Intf" not implemented') + v9.CheckSourceFailure(lines, 'E1349: Function "_Foo" of interface "Intf" not implemented') enddef " Test for using the return value of a class/object method as a function @@ -3751,7 +3910,7 @@ def Test_objmethod_funcarg() var t = C.new() Baz(t) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) lines =<< trim END vim9script @@ -3772,7 +3931,7 @@ def Test_objmethod_funcarg() Baz() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef def Test_static_inheritence() @@ -3797,21 +3956,17 @@ def Test_static_inheritence() class B extends A def new() - _svar = 2 this._mvar = 102 enddef endclass class C extends B def new() - _svar = 3 this._mvar = 103 enddef def AccessPrivateStaticThroughClassName(): number assert_equal(1, A._svar) - assert_equal(2, B._svar) - assert_equal(3, C._svar) return 444 enddef endclass @@ -3823,14 +3978,14 @@ def Test_static_inheritence() assert_equal(102, ob.AccessObject()) assert_equal(103, oc.AccessObject()) - assert_equal(444, oc.AccessPrivateStaticThroughClassName()) + assert_fails('echo oc.AccessPrivateStaticThroughClassName()', 'E1333: Cannot access private member: _svar') # verify object properly resolves to correct static assert_equal(1, oa.AccessStaticThroughObject()) - assert_equal(2, ob.AccessStaticThroughObject()) - assert_equal(3, oc.AccessStaticThroughObject()) + assert_equal(1, ob.AccessStaticThroughObject()) + assert_equal(1, oc.AccessStaticThroughObject()) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef " Test for declaring duplicate object and class members @@ -3843,7 +3998,7 @@ def Test_dup_member_variable() this.val = 20 endclass END - v9.CheckScriptFailure(lines, 'E1369: Duplicate member: val') + v9.CheckSourceFailure(lines, 'E1369: Duplicate member: val') # Duplicate private member variable lines =<< trim END @@ -3853,7 +4008,7 @@ def Test_dup_member_variable() this._val = 20 endclass END - v9.CheckScriptFailure(lines, 'E1369: Duplicate member: _val') + v9.CheckSourceFailure(lines, 'E1369: Duplicate member: _val') # Duplicate public member variable lines =<< trim END @@ -3863,7 +4018,7 @@ def Test_dup_member_variable() public this.val = 20 endclass END - v9.CheckScriptFailure(lines, 'E1369: Duplicate member: val') + v9.CheckSourceFailure(lines, 'E1369: Duplicate member: val') # Duplicate private member variable lines =<< trim END @@ -3873,7 +4028,7 @@ def Test_dup_member_variable() this._val = 20 endclass END - v9.CheckScriptFailure(lines, 'E1369: Duplicate member: _val') + v9.CheckSourceFailure(lines, 'E1369: Duplicate member: _val') # Duplicate public and private member variable lines =<< trim END @@ -3883,7 +4038,7 @@ def Test_dup_member_variable() public this.val = 10 endclass END - v9.CheckScriptFailure(lines, 'E1369: Duplicate member: val') + v9.CheckSourceFailure(lines, 'E1369: Duplicate member: val') # Duplicate class member variable lines =<< trim END @@ -3893,7 +4048,7 @@ def Test_dup_member_variable() static _s: string = "def" endclass END - v9.CheckScriptFailure(lines, 'E1369: Duplicate member: _s') + v9.CheckSourceFailure(lines, 'E1369: Duplicate member: _s') # Duplicate public and private class member variable lines =<< trim END @@ -3903,7 +4058,7 @@ def Test_dup_member_variable() static _s: string = "def" endclass END - v9.CheckScriptFailure(lines, 'E1369: Duplicate member: _s') + v9.CheckSourceFailure(lines, 'E1369: Duplicate member: _s') # Duplicate class and object member variable lines =<< trim END @@ -3918,7 +4073,7 @@ def Test_dup_member_variable() assert_equal(10, C.val) assert_equal(20, c.val) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # Duplicate object member variable in a derived class lines =<< trim END @@ -3932,7 +4087,7 @@ def Test_dup_member_variable() this.val = 20 endclass END - v9.CheckScriptFailure(lines, 'E1369: Duplicate member: val') + v9.CheckSourceFailure(lines, 'E1369: Duplicate member: val') # Duplicate object private member variable in a derived class lines =<< trim END @@ -3946,7 +4101,7 @@ def Test_dup_member_variable() this._val = 20 endclass END - v9.CheckScriptFailure(lines, 'E1369: Duplicate member: _val') + v9.CheckSourceFailure(lines, 'E1369: Duplicate member: _val') # Duplicate object private member variable in a derived class lines =<< trim END @@ -3960,7 +4115,7 @@ def Test_dup_member_variable() this._val = 20 endclass END - v9.CheckScriptFailure(lines, 'E1369: Duplicate member: _val') + v9.CheckSourceFailure(lines, 'E1369: Duplicate member: _val') # Duplicate object member variable in a derived class lines =<< trim END @@ -3974,63 +4129,7 @@ def Test_dup_member_variable() this.val = 20 endclass END - v9.CheckScriptFailure(lines, 'E1369: Duplicate member: val') - - # Duplicate class member variable in a derived class - lines =<< trim END - vim9script - class A - static val = 10 - endclass - class B extends A - endclass - class C extends B - static val = 20 - endclass - END - v9.CheckScriptFailure(lines, 'E1369: Duplicate member: val') - - # Duplicate private class member variable in a derived class - lines =<< trim END - vim9script - class A - static _val = 10 - endclass - class B extends A - endclass - class C extends B - static _val = 20 - endclass - END - v9.CheckScriptFailure(lines, 'E1369: Duplicate member: _val') - - # Duplicate private class member variable in a derived class - lines =<< trim END - vim9script - class A - static val = 10 - endclass - class B extends A - endclass - class C extends B - static _val = 20 - endclass - END - v9.CheckScriptFailure(lines, 'E1369: Duplicate member: _val') - - # Duplicate class member variable in a derived class - lines =<< trim END - vim9script - class A - static _val = 10 - endclass - class B extends A - endclass - class C extends B - static val = 20 - endclass - END - v9.CheckScriptFailure(lines, 'E1369: Duplicate member: val') + v9.CheckSourceFailure(lines, 'E1369: Duplicate member: val') # Two member variables with a common prefix lines =<< trim END @@ -4040,7 +4139,7 @@ def Test_dup_member_variable() public static svar: number endclass END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef def Test_interface_static_member_access() @@ -4058,7 +4157,7 @@ def Test_interface_static_member_access() endclass C.new().F() END - v9.CheckScriptFailure(lines, 'E1409: Cannot directly access interface "I" static member "num"') + v9.CheckSourceFailure(lines, 'E1409: Cannot directly access interface "I" static member "num"') # In a class cannot write to interface static lines =<< trim END @@ -4074,7 +4173,7 @@ def Test_interface_static_member_access() endclass C.new().F() END - v9.CheckScriptFailure(lines, 'E1409: Cannot directly access interface "I" static member "num"') + v9.CheckSourceFailure(lines, 'E1409: Cannot directly access interface "I" static member "num"') # In a def cannot read from interface static lines =<< trim END @@ -4087,7 +4186,7 @@ def Test_interface_static_member_access() enddef F() END - v9.CheckScriptFailure(lines, 'E1409: Cannot directly access interface "I" static member "num"') + v9.CheckSourceFailure(lines, 'E1409: Cannot directly access interface "I" static member "num"') # In a def cannot write to interface static lines =<< trim END @@ -4100,7 +4199,7 @@ def Test_interface_static_member_access() enddef F() END - v9.CheckScriptFailure(lines, 'E1409: Cannot directly access interface "I" static member "num"') + v9.CheckSourceFailure(lines, 'E1409: Cannot directly access interface "I" static member "num"') # script level cannot read interface static lines =<< trim END @@ -4111,7 +4210,7 @@ def Test_interface_static_member_access() var x = I.s_var1 END - v9.CheckScriptFailure(lines, 'E1409: Cannot directly access interface "I" static member "s_var1"') + v9.CheckSourceFailure(lines, 'E1409: Cannot directly access interface "I" static member "s_var1"') # script level cannot write interface static lines =<< trim END @@ -4122,7 +4221,7 @@ def Test_interface_static_member_access() I.s_var1 = 3 END - v9.CheckScriptFailure(lines, 'E1409: Cannot directly access interface "I" static member "I.s_var1 = 3"') + v9.CheckSourceFailure(lines, 'E1409: Cannot directly access interface "I" static member "I.s_var1 = 3"') enddef @@ -4158,7 +4257,7 @@ def Test_static_member_access_outside_class() assert_equal(11, F1()) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef " Test for accessing a private member outside a class in a def function @@ -4178,7 +4277,7 @@ def Test_private_member_access_outside_class() enddef T() END - v9.CheckScriptFailure(lines, 'E1333: Cannot access private member: _val') + v9.CheckSourceFailure(lines, 'E1333: Cannot access private member: _val') # access a non-existing private object member variable lines =<< trim END @@ -4192,7 +4291,7 @@ def Test_private_member_access_outside_class() enddef T() END - v9.CheckScriptFailure(lines, 'E1089: Unknown variable: _a = 1') + v9.CheckSourceFailure(lines, 'E1089: Unknown variable: _a') # private static member variable lines =<< trim END @@ -4206,7 +4305,7 @@ def Test_private_member_access_outside_class() enddef T() END - v9.CheckScriptFailure(lines, 'E1326: Member not found on object "A": _val') + v9.CheckSourceFailure(lines, 'E1375: Class member "_val" accessible only using class "A"') # private static member variable lines =<< trim END @@ -4220,8 +4319,7 @@ def Test_private_member_access_outside_class() enddef T() END - # TODO: wrong error, should be about private member - v9.CheckScriptFailure(lines, 'E1089: Unknown variable') + v9.CheckSourceFailure(lines, 'E1374: Class member "_val" accessible only inside class "A"') # private static class variable lines =<< trim END @@ -4234,7 +4332,7 @@ def Test_private_member_access_outside_class() enddef T() END - v9.CheckScriptFailure(lines, 'E1333: Cannot access private member: _val') + v9.CheckSourceFailure(lines, 'E1333: Cannot access private member: _val') # private static class variable lines =<< trim END @@ -4247,7 +4345,7 @@ def Test_private_member_access_outside_class() enddef T() END - v9.CheckScriptFailure(lines, 'E1333: Cannot access private member: _val') + v9.CheckSourceFailure(lines, 'E1333: Cannot access private member: _val') enddef " Test for changing the member access of an interface in a implementation class @@ -4261,7 +4359,7 @@ def Test_change_interface_member_access() this.val = 10 endclass END - v9.CheckScriptFailure(lines, 'E1367: Access level of member "val" of interface "A" is different') + v9.CheckSourceFailure(lines, 'E1367: Access level of member "val" of interface "A" is different') lines =<< trim END vim9script @@ -4272,7 +4370,7 @@ def Test_change_interface_member_access() public this.val = 10 endclass END - v9.CheckScriptFailure(lines, 'E1367: Access level of member "val" of interface "A" is different') + v9.CheckSourceFailure(lines, 'E1367: Access level of member "val" of interface "A" is different') enddef " Test for trying to change a readonly member from a def function @@ -4288,7 +4386,7 @@ def Test_readonly_member_change_in_def_func() enddef T() END - v9.CheckScriptFailure(lines, 'E46: Cannot change read-only variable "val"') + v9.CheckSourceFailure(lines, 'E46: Cannot change read-only variable "val"') enddef " Test for reading and writing a class member from a def function @@ -4312,7 +4410,7 @@ def Test_modify_class_member_from_def_function() enddef T() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef " Test for accessing a class member variable using an object @@ -4337,7 +4435,7 @@ def Test_class_variable_access_using_object() enddef Foo() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # Cannot read from a class variable using an object in script context lines =<< trim END @@ -4350,7 +4448,7 @@ def Test_class_variable_access_using_object() var a = A.new() echo a.svar2 END - v9.CheckScriptFailure(lines, 'E1326: Member not found on object "A": svar2') + v9.CheckSourceFailure(lines, 'E1375: Class member "svar2" accessible only using class "A"') # Cannot write to a class variable using an object in script context lines =<< trim END @@ -4363,7 +4461,7 @@ def Test_class_variable_access_using_object() var a = A.new() a.svar2 = [2] END - v9.CheckScriptFailure(lines, 'E1334: Object member not found: svar2 = [2]') + v9.CheckSourceFailure(lines, 'E1375: Class member "svar2" accessible only using class "A"') # Cannot read from a class variable using an object in def method context lines =<< trim END @@ -4379,7 +4477,7 @@ def Test_class_variable_access_using_object() enddef T() END - v9.CheckScriptFailure(lines, 'E1326: Member not found on object "A": svar2') + v9.CheckSourceFailure(lines, 'E1375: Class member "svar2" accessible only using class "A"') # Cannot write to a class variable using an object in def method context lines =<< trim END @@ -4395,7 +4493,7 @@ def Test_class_variable_access_using_object() enddef T() END - v9.CheckScriptFailure(lines, 'E1089: Unknown variable: svar2 = [2]') + v9.CheckSourceFailure(lines, 'E1374: Class member "svar2" accessible only inside class "A"') enddef " Test for using a interface method using a child object @@ -4431,7 +4529,7 @@ def Test_interface_method_from_child() T1(c) T2(c) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef " Test for using an interface method using a child object when it is overridden @@ -4472,7 +4570,7 @@ enddef " T1(c) " T2(c) " END -" v9.CheckScriptSuccess(lines) +" v9.CheckSourceSuccess(lines) " enddef " Test for abstract methods @@ -4498,7 +4596,7 @@ def Test_abstract_method() var b = B.new() assert_equal([10, 20, 30], [b.M1(), b.M2(), b.M3()]) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # Don't define an abstract method lines =<< trim END @@ -4509,7 +4607,7 @@ def Test_abstract_method() class B extends A endclass END - v9.CheckScriptFailure(lines, 'E1373: Abstract method "Foo" is not implemented') + v9.CheckSourceFailure(lines, 'E1373: Abstract method "Foo" is not implemented') # Use abstract method in a concrete class lines =<< trim END @@ -4520,7 +4618,7 @@ def Test_abstract_method() class B extends A endclass END - v9.CheckScriptFailure(lines, 'E1372: Abstract method "abstract def Foo()" cannot be defined in a concrete class') + v9.CheckSourceFailure(lines, 'E1372: Abstract method "abstract def Foo()" cannot be defined in a concrete class') # Use abstract method in an interface lines =<< trim END @@ -4531,7 +4629,7 @@ def Test_abstract_method() class B implements A endclass END - v9.CheckScriptFailure(lines, 'E1372: Abstract method "abstract def Foo()" cannot be defined in a concrete class') + v9.CheckSourceFailure(lines, 'E1372: Abstract method "abstract def Foo()" cannot be defined in a concrete class') # Abbreviate the "abstract" keyword lines =<< trim END @@ -4540,7 +4638,7 @@ def Test_abstract_method() abs def Foo() endclass END - v9.CheckScriptFailure(lines, 'E1065: Command cannot be shortened: abs def Foo()') + v9.CheckSourceFailure(lines, 'E1065: Command cannot be shortened: abs def Foo()') # Use "abstract" with a member variable lines =<< trim END @@ -4549,7 +4647,7 @@ def Test_abstract_method() abstract this.val = 10 endclass END - v9.CheckScriptFailure(lines, 'E1371: Abstract must be followed by "def" or "static"') + v9.CheckSourceFailure(lines, 'E1371: Abstract must be followed by "def" or "static"') # Use a static abstract method lines =<< trim END @@ -4564,7 +4662,7 @@ def Test_abstract_method() endclass assert_equal(4, B.Foo()) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # Type mismatch between abstract method and concrete method lines =<< trim END @@ -4578,7 +4676,7 @@ def Test_abstract_method() enddef endclass END - v9.CheckScriptFailure(lines, 'E1407: Method "Foo": type mismatch, expected func(string, number): list but got func(number, string): list') + v9.CheckSourceFailure(lines, 'E1407: Method "Foo": type mismatch, expected func(string, number): list but got func(number, string): list') # Use an abstract class to invoke an abstract method # FIXME: This should fail @@ -4589,7 +4687,7 @@ def Test_abstract_method() endclass A.Foo() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # Invoke an abstract method from a def function lines =<< trim END @@ -4608,7 +4706,31 @@ def Test_abstract_method() var b = B.new() Bar(b) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) +enddef + +" Test for calling a class method from a subclass +def Test_class_method_call_from_subclass() + # class method call from a subclass + var lines =<< trim END + vim9script + + class A + static def Foo() + echo "foo" + enddef + endclass + + class B extends A + def Bar() + Foo() + enddef + endclass + + var b = B.new() + b.Bar() + END + v9.CheckSourceFailure(lines, 'E1374: Class member "Foo" accessible only inside class "A"') enddef " Test for calling a class method using an object in a def function context and @@ -4638,7 +4760,7 @@ def Test_class_method_call_using_object() a.Bar() T() END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) # script context lines =<< trim END @@ -4652,7 +4774,7 @@ def Test_class_method_call_using_object() var a = A.new() assert_equal('foo', a.Foo()) END - v9.CheckScriptFailure(lines, 'E1325: Method not found on class "A": Foo()') + v9.CheckSourceFailure(lines, 'E1375: Class member "Foo" accessible only using class "A"') # def function context lines =<< trim END @@ -4669,7 +4791,407 @@ def Test_class_method_call_using_object() enddef T() END - v9.CheckScriptFailure(lines, 'E1325: Method not found on class "A": Foo()') + v9.CheckSourceFailure(lines, 'E1375: Class member "Foo" accessible only using class "A"') +enddef + +def Test_class_variable() + var lines =<< trim END + vim9script + + class A + public static val: number = 10 + static def ClassFunc() + assert_equal(10, val) + enddef + def ObjFunc() + assert_equal(10, val) + enddef + endclass + + class B extends A + endclass + + assert_equal(10, A.val) + A.ClassFunc() + var a = A.new() + a.ObjFunc() + var b = B.new() + b.ObjFunc() + + def T1(a1: A) + a1.ObjFunc() + A.ClassFunc() + enddef + T1(b) + + A.val = 20 + assert_equal(20, A.val) + END + v9.CheckSourceSuccess(lines) + + # Modifying a parent class variable from a child class method + lines =<< trim END + vim9script + + class A + static val: number = 10 + endclass + + class B extends A + static def ClassFunc() + val = 20 + enddef + endclass + B.ClassFunc() + END + v9.CheckSourceFailure(lines, 'E1374: Class member "val" accessible only inside class "A"') + + # Reading a parent class variable from a child class method + lines =<< trim END + vim9script + + class A + static val: number = 10 + endclass + + class B extends A + static def ClassFunc() + var i = val + enddef + endclass + B.ClassFunc() + END + v9.CheckSourceFailure(lines, 'E1374: Class member "val" accessible only inside class "A"') + + # Modifying a parent class variable from a child object method + lines =<< trim END + vim9script + + class A + static val: number = 10 + endclass + + class B extends A + def ObjFunc() + val = 20 + enddef + endclass + var b = B.new() + b.ObjFunc() + END + v9.CheckSourceFailure(lines, 'E1374: Class member "val" accessible only inside class "A"') + + # Reading a parent class variable from a child object method + lines =<< trim END + vim9script + + class A + static val: number = 10 + endclass + + class B extends A + def ObjFunc() + var i = val + enddef + endclass + var b = B.new() + b.ObjFunc() + END + v9.CheckSourceFailure(lines, 'E1374: Class member "val" accessible only inside class "A"') + + # Modifying a class variable using an object at script level + lines =<< trim END + vim9script + + class A + static val: number = 10 + endclass + var a = A.new() + a.val = 20 + END + v9.CheckSourceFailure(lines, 'E1375: Class member "val" accessible only using class "A"') + + # Reading a class variable using an object at script level + lines =<< trim END + vim9script + + class A + static val: number = 10 + endclass + var a = A.new() + var i = a.val + END + v9.CheckSourceFailure(lines, 'E1375: Class member "val" accessible only using class "A"') + + # Modifying a class variable using an object at function level + lines =<< trim END + vim9script + + class A + static val: number = 10 + endclass + + def T() + var a = A.new() + a.val = 20 + enddef + T() + END + v9.CheckSourceFailure(lines, 'E1374: Class member "val" accessible only inside class "A"') + + # Reading a class variable using an object at function level + lines =<< trim END + vim9script + + class A + static val: number = 10 + endclass + def T() + var a = A.new() + var i = a.val + enddef + T() + END + v9.CheckSourceFailure(lines, 'E1375: Class member "val" accessible only using class "A"') +enddef + +" Test for using a duplicate class method and class variable in a child class +def Test_dup_class_member() + # duplicate class variable, class method and overridden object method + var lines =<< trim END + vim9script + class A + static sval = 100 + static def Check() + assert_equal(100, sval) + enddef + def GetVal(): number + return sval + enddef + endclass + + class B extends A + static sval = 200 + static def Check() + assert_equal(200, sval) + enddef + def GetVal(): number + return sval + enddef + endclass + + def T1(aa: A): number + return aa.GetVal() + enddef + + def T2(bb: B): number + return bb.GetVal() + enddef + + assert_equal(100, A.sval) + assert_equal(200, B.sval) + var a = A.new() + assert_equal(100, a.GetVal()) + var b = B.new() + assert_equal(200, b.GetVal()) + assert_equal(200, T1(b)) + assert_equal(200, T2(b)) + END + v9.CheckSourceSuccess(lines) + + # duplicate class variable and class method + lines =<< trim END + vim9script + class A + static sval = 100 + static def Check() + assert_equal(100, sval) + enddef + def GetVal(): number + return sval + enddef + endclass + + class B extends A + static sval = 200 + static def Check() + assert_equal(200, sval) + enddef + endclass + + def T1(aa: A): number + return aa.GetVal() + enddef + + def T2(bb: B): number + return bb.GetVal() + enddef + + assert_equal(100, A.sval) + assert_equal(200, B.sval) + var a = A.new() + assert_equal(100, a.GetVal()) + var b = B.new() + assert_equal(100, b.GetVal()) + assert_equal(100, T1(b)) + assert_equal(100, T2(b)) + END + v9.CheckSourceSuccess(lines) +enddef + +" Test for calling an instance method using the class +def Test_instance_method_call_using_class() + # Invoke an object method using a class in script context + var lines =<< trim END + vim9script + class A + def Foo() + echo "foo" + enddef + endclass + A.Foo() + END + v9.CheckSourceFailure(lines, 'E1376: Object member "Foo" accessible only using class "A" object') + + # Invoke an object method using a class in def function context + lines =<< trim END + vim9script + class A + def Foo() + echo "foo" + enddef + endclass + def T() + A.Foo() + enddef + T() + END + v9.CheckSourceFailure(lines, 'E1376: Object member "Foo" accessible only using class "A" object') +enddef + +" Test for duplicate class method and instance method +def Test_dup_classmethod_objmethod() + # Duplicate instance method + var lines =<< trim END + vim9script + class A + static def Foo() + enddef + def Foo() + enddef + endclass + END + v9.CheckSourceFailure(lines, 'E1355: Duplicate function: Foo') + + # Duplicate private instance method + lines =<< trim END + vim9script + class A + static def Foo() + enddef + def _Foo() + enddef + endclass + END + v9.CheckSourceFailure(lines, 'E1355: Duplicate function: _Foo') + + # Duplicate class method + lines =<< trim END + vim9script + class A + def Foo() + enddef + static def Foo() + enddef + endclass + END + v9.CheckSourceFailure(lines, 'E1355: Duplicate function: Foo') + + # Duplicate private class method + lines =<< trim END + vim9script + class A + def Foo() + enddef + static def _Foo() + enddef + endclass + END + v9.CheckSourceFailure(lines, 'E1355: Duplicate function: _Foo') + + # Duplicate private class and object method + lines =<< trim END + vim9script + class A + def _Foo() + enddef + static def _Foo() + enddef + endclass + END + v9.CheckSourceFailure(lines, 'E1355: Duplicate function: _Foo') +enddef + +" Test for an instance method access level comparison with parent instance +" methods. +def Test_instance_method_access_level() + # Private method in subclass + var lines =<< trim END + vim9script + class A + def Foo() + enddef + endclass + class B extends A + endclass + class C extends B + def _Foo() + enddef + endclass + END + v9.CheckSourceFailure(lines, 'E1378: Access level of method "_Foo" is different in class "A"') + + # Public method in subclass + lines =<< trim END + vim9script + class A + def _Foo() + enddef + endclass + class B extends A + endclass + class C extends B + def Foo() + enddef + endclass + END + v9.CheckSourceFailure(lines, 'E1378: Access level of method "Foo" is different in class "A"') +enddef + +def Test_extend_empty_class() + var lines =<< trim END + vim9script + class A + endclass + class B extends A + endclass + class C extends B + public static rw_class_var = 1 + public this.rw_obj_var = 2 + static def ClassMethod(): number + return 3 + enddef + def ObjMethod(): number + return 4 + enddef + endclass + assert_equal(1, C.rw_class_var) + assert_equal(3, C.ClassMethod()) + var c = C.new() + assert_equal(2, c.rw_obj_var) + assert_equal(4, c.ObjMethod()) + END + v9.CheckSourceSuccess(lines) enddef " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/testdir/vim9.vim b/src/testdir/vim9.vim index 5877a79ef..782809bde 100644 --- a/src/testdir/vim9.vim +++ b/src/testdir/vim9.vim @@ -110,6 +110,40 @@ export def CheckScriptSuccess(lines: list) endtry enddef +# :source a list of "lines" and check whether it fails with "error" +export def CheckSourceFailure(lines: list, error: string, lnum = -3) + new + setline(1, lines) + try + assert_fails('source', error, lines, lnum) + finally + bw! + endtry +enddef + +# :source a list of "lines" and check whether it fails with the list of +# "errors" +export def CheckSourceFailureList(lines: list, errors: list, lnum = -3) + new + setline(1, lines) + try + assert_fails('source', errors, lines, lnum) + finally + bw! + endtry +enddef + +# :source a list of "lines" and check whether it succeeds +export def CheckSourceSuccess(lines: list) + new + setline(1, lines) + try + :source + finally + bw! + endtry +enddef + export def CheckDefAndScriptSuccess(lines: list) CheckDefSuccess(lines) CheckScriptSuccess(['vim9script'] + lines) diff --git a/src/version.c b/src/version.c index aaa50da4b..ba4be2780 100644 --- a/src/version.c +++ b/src/version.c @@ -699,6 +699,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1898, /**/ 1897, /**/ diff --git a/src/vim9class.c b/src/vim9class.c index ccc381838..bf7d63295 100644 --- a/src/vim9class.c +++ b/src/vim9class.c @@ -322,63 +322,109 @@ validate_extends_class(char_u *extends_name, class_T **extends_clp) } /* - * Check whether a class/object member variable in "classmembers_gap" / - * "objmembers_gap" is a duplicate of a member in any of the extended parent - * class lineage. Returns TRUE if there are no duplicates. + * Check method names in the parent class lineage to make sure the access is + * the same for overridden methods. + */ + static int +validate_extends_methods( + garray_T *objmethods_gap, + class_T *extends_cl) +{ + class_T *super = extends_cl; + int method_count = objmethods_gap->ga_len; + ufunc_T **cl_fp = (ufunc_T **)(objmethods_gap->ga_data); + + while (super != NULL) + { + int extends_method_count = super->class_obj_method_count_child; + if (extends_method_count == 0) + { + super = super->class_extends; + continue; + } + + ufunc_T **extends_methods = super->class_obj_methods; + + for (int i = 0; i < extends_method_count; i++) + { + char_u *pstr = extends_methods[i]->uf_name; + int extends_private = (*pstr == '_'); + if (extends_private) + pstr++; + + for (int j = 0; j < method_count; j++) + { + char_u *qstr = cl_fp[j]->uf_name; + int priv_method = (*qstr == '_'); + if (priv_method) + qstr++; + if (STRCMP(pstr, qstr) == 0 && priv_method != extends_private) + { + // Method access is different between the super class and + // the subclass + semsg(_(e_method_str_of_class_str_has_different_access), + cl_fp[j]->uf_name, super->class_name); + return FALSE; + } + } + } + super = super->class_extends; + } + + return TRUE; +} + +/* + * Check whether a object member variable in "objmembers_gap" is a duplicate of + * a member in any of the extended parent class lineage. Returns TRUE if there + * are no duplicates. */ static int validate_extends_members( - garray_T *classmembers_gap, garray_T *objmembers_gap, class_T *extends_cl) { - for (int loop = 1; loop <= 2; ++loop) - { - // loop == 1: check class members - // loop == 2: check object members - int member_count = loop == 1 ? classmembers_gap->ga_len - : objmembers_gap->ga_len; - if (member_count == 0) - continue; - ocmember_T *members = (ocmember_T *)(loop == 1 - ? classmembers_gap->ga_data - : objmembers_gap->ga_data); + // loop == 1: check class members + // loop == 2: check object members + int member_count = objmembers_gap->ga_len; + if (member_count == 0) + return TRUE; - // Validate each member variable - for (int c_i = 0; c_i < member_count; c_i++) - { - class_T *p_cl = extends_cl; - ocmember_T *c_m = members + c_i; - char_u *pstr = (*c_m->ocm_name == '_') + ocmember_T *members = (ocmember_T *)(objmembers_gap->ga_data); + + // Validate each member variable + for (int c_i = 0; c_i < member_count; c_i++) + { + class_T *p_cl = extends_cl; + ocmember_T *c_m = members + c_i; + char_u *pstr = (*c_m->ocm_name == '_') ? c_m->ocm_name + 1 : c_m->ocm_name; - // Check in all the parent classes in the lineage - while (p_cl != NULL) + // Check in all the parent classes in the lineage + while (p_cl != NULL) + { + int p_member_count = p_cl->class_obj_member_count; + if (p_member_count == 0) { - int p_member_count = loop == 1 - ? p_cl->class_class_member_count - : p_cl->class_obj_member_count; - if (p_member_count == 0) - continue; - ocmember_T *p_members = (loop == 1 - ? p_cl->class_class_members - : p_cl->class_obj_members); - - // Compare against all the members in the parent class - for (int p_i = 0; p_i < p_member_count; p_i++) - { - ocmember_T *p_m = p_members + p_i; - char_u *qstr = (*p_m->ocm_name == '_') - ? p_m->ocm_name + 1 : p_m->ocm_name; - if (STRCMP(pstr, qstr) == 0) - { - semsg(_(e_duplicate_member_str), c_m->ocm_name); - return FALSE; - } - } - p_cl = p_cl->class_extends; + continue; } + ocmember_T *p_members = p_cl->class_obj_members; + + // Compare against all the members in the parent class + for (int p_i = 0; p_i < p_member_count; p_i++) + { + ocmember_T *p_m = p_members + p_i; + char_u *qstr = (*p_m->ocm_name == '_') + ? p_m->ocm_name + 1 : p_m->ocm_name; + if (STRCMP(pstr, qstr) == 0) + { + semsg(_(e_duplicate_member_str), c_m->ocm_name); + return FALSE; + } + } + + p_cl = p_cl->class_extends; } } @@ -391,7 +437,7 @@ validate_extends_members( * implemented. */ static int -validate_extends_methods( +validate_abstract_class_methods( garray_T *classmethods_gap, garray_T *objmethods_gap, class_T *extends_cl) @@ -707,18 +753,26 @@ is_duplicate_member(garray_T *mgap, char_u *varname, char_u *varname_end) * Returns TRUE if the method "name" is already defined. */ static int -is_duplicate_method(garray_T *fgap, char_u *name) +is_duplicate_method( + garray_T *classmethods_gap, + garray_T *objmethods_gap, + char_u *name) { char_u *pstr = (*name == '_') ? name + 1 : name; - for (int i = 0; i < fgap->ga_len; ++i) + // loop 1: class methods, loop 2: object methods + for (int loop = 1; loop <= 2; loop++) { - char_u *n = ((ufunc_T **)fgap->ga_data)[i]->uf_name; - char_u *qstr = *n == '_' ? n + 1 : n; - if (STRCMP(pstr, qstr) == 0) + garray_T *fgap = (loop == 1) ? classmethods_gap : objmethods_gap; + for (int i = 0; i < fgap->ga_len; ++i) { - semsg(_(e_duplicate_function_str), name); - return TRUE; + char_u *n = ((ufunc_T **)fgap->ga_data)[i]->uf_name; + char_u *qstr = *n == '_' ? n + 1 : n; + if (STRCMP(pstr, qstr) == 0) + { + semsg(_(e_duplicate_function_str), name); + return TRUE; + } } } @@ -882,7 +936,7 @@ add_lookup_tables(class_T *cl, class_T *extends_cl, garray_T *objmethods_gap) return FAIL; } - // Update the lookup table for the extended class, if nay + // Update the lookup table for the extended class, if any if (extends_cl != NULL) { class_T *pclass = extends_cl; @@ -1017,9 +1071,10 @@ add_classfuncs_objmethods( int parent_count = 0; if (extends_cl != NULL) - // Include functions from the parent. + // Include object methods from the parent. + // Don't include the parent class methods. parent_count = loop == 1 - ? extends_cl->class_class_function_count + ? 0 : extends_cl->class_obj_method_count; *fcount = parent_count + gap->ga_len; @@ -1087,6 +1142,8 @@ add_classfuncs_objmethods( { ufunc_T *fp = (*fup)[i]; fp->uf_class = cl; + if (i < gap->ga_len) + fp->uf_defclass = cl; if (loop == 2) fp->uf_flags |= FC_OBJECT; } @@ -1443,16 +1500,16 @@ early_ret: break; } - garray_T *fgap = has_static || is_new - ? &classfunctions : &objmethods; // Check the name isn't used already. - if (is_duplicate_method(fgap, name)) + if (is_duplicate_method(&classfunctions, &objmethods, name)) { success = FALSE; func_clear_free(uf, FALSE); break; } + garray_T *fgap = has_static || is_new + ? &classfunctions : &objmethods; if (ga_grow(fgap, 1) == OK) { if (is_new) @@ -1517,19 +1574,23 @@ early_ret: success = validate_extends_class(extends, &extends_cl); VIM_CLEAR(extends); - // Check the new class members and object members are not duplicates of the - // members in the extended class lineage. + // Check the new object methods to make sure their access (public or + // private) is the same as that in the extended class lineage. if (success && extends_cl != NULL) - success = validate_extends_members(&classmembers, &objmembers, - extends_cl); + success = validate_extends_methods(&objmethods, extends_cl); + + // Check the new class and object variables are not duplicates of the + // variables in the extended class lineage. + if (success && extends_cl != NULL) + success = validate_extends_members(&objmembers, extends_cl); // When extending an abstract class, make sure all the abstract methods in // the parent class are implemented. If the current class is an abstract // class, then there is no need for this check. if (success && !is_abstract && extends_cl != NULL && (extends_cl->class_flags & CLASS_ABSTRACT)) - success = validate_extends_methods(&classfunctions, &objmethods, - extends_cl); + success = validate_abstract_class_methods(&classfunctions, + &objmethods, extends_cl); class_T **intf_classes = NULL; @@ -1572,12 +1633,10 @@ early_ret: extends_cl->class_flags |= CLASS_EXTENDED; } - // Add class and object members to "cl". + // Add class and object variables to "cl". if (add_members_to_class(&classmembers, - extends_cl == NULL ? NULL - : extends_cl->class_class_members, - extends_cl == NULL ? 0 - : extends_cl->class_class_member_count, + NULL, + 0, &cl->class_class_members, &cl->class_class_member_count) == FAIL || add_members_to_class(&objmembers, @@ -1756,7 +1815,21 @@ class_member_type( member_idx); if (m == NULL) { - semsg(_(e_unknown_variable_str), name); + char_u *varname = vim_strnsave(name, len); + if (varname != NULL) + { + if (is_object && class_member_idx(cl, name, len) >= 0) + // A class variable with this name is present + semsg(_(e_class_member_str_accessible_only_inside_class_str), + varname, cl->class_name); + else if (!is_object && object_member_idx(cl, name, len) >= 0) + // An instance variable with this name is present + semsg(_(e_object_member_str_accessible_only_using_object_str), + varname, cl->class_name); + else + semsg(_(e_unknown_variable_str), varname); + } + vim_free(varname); return &t_any; } @@ -1887,8 +1960,7 @@ class_object_index( fp = method_lookup(cl, rettv->v_type, name, len, NULL); if (fp == NULL) { - semsg(_(e_method_not_found_on_class_str_str), cl->class_name, - name); + method_not_found_msg(cl, rettv->v_type, name, len); return FAIL; } @@ -1951,7 +2023,7 @@ class_object_index( return OK; } - semsg(_(e_member_not_found_on_object_str_str), cl->class_name, name); + member_not_found_msg(cl, VAR_OBJECT, name, len); } else if (rettv->v_type == VAR_CLASS) @@ -1962,7 +2034,7 @@ class_object_index( ocmember_T *m = class_member_lookup(cl, name, len, &m_idx); if (m == NULL) { - semsg(_(e_member_not_found_on_class_str_str), cl->class_name, name); + member_not_found_msg(cl, VAR_CLASS, name, len); return FAIL; } @@ -2029,7 +2101,7 @@ fail_after_eval: } /* - * Returns the index of class member variable "name" in the class "cl". + * Returns the index of class variable "name" in the class "cl". * Returns -1, if the variable is not found. * If "namelen" is zero, then it is assumed that "name" is NUL terminated. */ @@ -2497,6 +2569,68 @@ object_free_nonref(int copyID) return did_free; } +/* + * Echo a class or object method not found message. + */ + void +method_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len) +{ + char_u *method_name = vim_strnsave(name, len); + if ((v_type == VAR_OBJECT) + && (class_method_idx(cl, name, len) >= 0)) + { + // If this is a class method, then give a different error + if (*name == '_') + semsg(_(e_cannot_access_private_method_str), method_name); + else + semsg(_(e_class_member_str_accessible_only_using_class_str), + method_name, cl->class_name); + } + else if ((v_type == VAR_CLASS) + && (object_method_idx(cl, name, len) >= 0)) + { + // If this is an object method, then give a different error + if (*name == '_') + semsg(_(e_cannot_access_private_method_str), method_name); + else + semsg(_(e_object_member_str_accessible_only_using_object_str), + method_name, cl->class_name); + } + else + semsg(_(e_method_not_found_on_class_str_str), cl->class_name, + method_name); + vim_free(method_name); +} + +/* + * Echo a class or object member not found message. + */ + void +member_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len) +{ + char_u *varname = len ? vim_strnsave(name, len) : vim_strsave(name); + + if (v_type == VAR_OBJECT) + { + if (class_member_idx(cl, name, len) >= 0) + semsg(_(e_class_member_str_accessible_only_using_class_str), + varname, cl->class_name); + else + semsg(_(e_member_not_found_on_object_str_str), cl->class_name, + varname); + } + else + { + if (object_member_idx(cl, name, len) >= 0) + semsg(_(e_object_member_str_accessible_only_using_object_str), + varname, cl->class_name); + else + semsg(_(e_class_member_str_not_found_in_class_str), + varname, cl->class_name); + } + vim_free(varname); +} + /* * Return TRUE when the class "cl", its base class or one of the implemented * interfaces matches the class "other_cl". diff --git a/src/vim9compile.c b/src/vim9compile.c index cc4aa4638..7de1b6253 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -332,24 +332,42 @@ script_var_exists(char_u *name, size_t len, cctx_T *cctx, cstack_T *cstack) } /* - * If "name[len]" is a class method in cctx->ctx_ufunc->uf_class return the - * class method index. + * Returns the index of a class method or class variable with name "name" + * accessible in the currently compiled function. * If "cl_ret" is not NULL set it to the class. * Otherwise return -1. */ - int -cctx_class_method_idx( + static int +cctx_class_midx( cctx_T *cctx, + int is_method, char_u *name, size_t len, class_T **cl_ret) { if (cctx == NULL || cctx->ctx_ufunc == NULL - || cctx->ctx_ufunc->uf_class == NULL) + || cctx->ctx_ufunc->uf_class == NULL + || cctx->ctx_ufunc->uf_defclass == NULL) return -1; - class_T *cl = cctx->ctx_ufunc->uf_class; - int m_idx = class_method_idx(cl, name, len); + // Search for the class method or variable in the class where the calling + // function is defined. + class_T *cl = cctx->ctx_ufunc->uf_defclass; + int m_idx = is_method ? class_method_idx(cl, name, len) + : class_member_idx(cl, name, len); + if (m_idx < 0) + { + cl = cl->class_extends; + while (cl != NULL) + { + m_idx = is_method ? class_method_idx(cl, name, len) + : class_member_idx(cl, name, len); + if (m_idx >= 0) + break; + cl = cl->class_extends; + } + } + if (m_idx >= 0) { if (cl_ret != NULL) @@ -360,10 +378,24 @@ cctx_class_method_idx( } /* - * If "name[len]" is a class member in cctx->ctx_ufunc->uf_class return the - * class member variable index. - * If "cl_ret" is not NULL set it to the class. - * Otherwise return -1; + * Returns the index of a class method with name "name" accessible in the + * currently compiled function. Returns -1 if not found. The class where the + * method is defined is returned in "cl_ret". + */ + int +cctx_class_method_idx( + cctx_T *cctx, + char_u *name, + size_t len, + class_T **cl_ret) +{ + return cctx_class_midx(cctx, TRUE, name, len, cl_ret); +} + +/* + * Returns the index of a class variable with name "name" accessible in the + * currently compiled function. Returns -1 if not found. The class where the + * variable is defined is returned in "cl_ret". */ int cctx_class_member_idx( @@ -372,19 +404,7 @@ cctx_class_member_idx( size_t len, class_T **cl_ret) { - if (cctx == NULL || cctx->ctx_ufunc == NULL - || cctx->ctx_ufunc->uf_class == NULL) - return -1; - - class_T *cl = cctx->ctx_ufunc->uf_class; - int m_idx = class_member_idx(cl, name, len); - if (m_idx >= 0) - { - if (cl_ret != NULL) - *cl_ret = cl; - } - - return m_idx; + return cctx_class_midx(cctx, FALSE, name, len, cl_ret); } /* @@ -1639,6 +1659,8 @@ compile_lhs( } else { + class_T *defcl; + // No specific kind of variable recognized, just a name. if (check_reserved_name(lhs->lhs_name, lhs->lhs_has_index && *var_end == '.') == FAIL) @@ -1681,8 +1703,16 @@ compile_lhs( } } else if ((lhs->lhs_classmember_idx = cctx_class_member_idx( - cctx, var_start, lhs->lhs_varlen, NULL)) >= 0) + cctx, var_start, lhs->lhs_varlen, &defcl)) >= 0) { + if (cctx->ctx_ufunc->uf_defclass != defcl) + { + // A class variable can be accessed without the class name + // only inside a class. + semsg(_(e_class_member_str_accessible_only_inside_class_str), + lhs->lhs_name, defcl->class_name); + return FAIL; + } if (is_decl) { semsg(_(e_variable_already_declared_in_class_str), @@ -1918,10 +1948,10 @@ compile_lhs( int use_class = lhs->lhs_type != NULL && (lhs->lhs_type->tt_type == VAR_CLASS - || lhs->lhs_type->tt_type == VAR_OBJECT); + || lhs->lhs_type->tt_type == VAR_OBJECT); if (lhs->lhs_type == NULL || (use_class ? lhs->lhs_type->tt_class == NULL - : lhs->lhs_type->tt_member == NULL)) + : lhs->lhs_type->tt_member == NULL)) { lhs->lhs_member_type = &t_any; } @@ -1930,9 +1960,10 @@ compile_lhs( // for an object or class member get the type of the member class_T *cl = lhs->lhs_type->tt_class; ocmember_T *m; + int is_object = lhs->lhs_type->tt_type == VAR_OBJECT; lhs->lhs_member_type = class_member_type(cl, - lhs->lhs_type->tt_type == VAR_OBJECT, + is_object, after + 1, lhs->lhs_end, &lhs->lhs_member_idx, &m); if (lhs->lhs_member_idx < 0) @@ -1946,7 +1977,11 @@ compile_lhs( } // If it is private member variable, then accessing it outside the // class is not allowed. - if ((m->ocm_access != VIM_ACCESS_ALL) && !inside_class(cctx, cl)) + // If it is a read only class variable, then it can be modified + // only inside the class where it is defined. + if ((m->ocm_access != VIM_ACCESS_ALL) && + ((is_object && !inside_class(cctx, cl)) + || (!is_object && cctx->ctx_ufunc->uf_class != cl))) { char *msg = (m->ocm_access == VIM_ACCESS_PRIVATE) ? e_cannot_access_private_member_str diff --git a/src/vim9execute.c b/src/vim9execute.c index f8e267641..7c61ff418 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -2172,8 +2172,7 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx) { if (*member == '_') { - semsg(_(e_cannot_access_private_member_str), - m->ocm_name); + semsg(_(e_cannot_access_private_member_str), m->ocm_name); status = FAIL; } @@ -2181,8 +2180,7 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx) } else { - semsg(_(e_member_not_found_on_object_str_str), - cl->class_name, member); + member_not_found_msg(cl, VAR_OBJECT, member, 0); status = FAIL; } } diff --git a/src/vim9expr.c b/src/vim9expr.c index 120a60627..a158f31ae 100644 --- a/src/vim9expr.c +++ b/src/vim9expr.c @@ -367,12 +367,19 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type) } if (ufunc == NULL) { - // TODO: different error for object method? - semsg(_(e_method_not_found_on_class_str_str), cl->class_name, name); + method_not_found_msg(cl, type->tt_type, name, len); return FAIL; } - if (*ufunc->uf_name == '_' && !inside_class_hierarchy(cctx, cl)) + // A private object method can be used only inside the class where it + // is defined or in one of the child classes. + // A private class method can be used only in the class where it is + // defined. + if (*ufunc->uf_name == '_' && + ((type->tt_type == VAR_OBJECT + && !inside_class_hierarchy(cctx, cl)) + || (type->tt_type == VAR_CLASS + && cctx->ctx_ufunc->uf_class != cl))) { semsg(_(e_cannot_access_private_method_str), name); return FAIL; @@ -422,7 +429,7 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type) return generate_FUNCREF(cctx, fp, NULL, 0, NULL); } - semsg(_(e_member_not_found_on_object_str_str), cl->class_name, name); + member_not_found_msg(cl, VAR_OBJECT, name, len); } else { @@ -438,7 +445,9 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type) cl->class_name, m->ocm_name); return FAIL; } - if (*name == '_' && !inside_class(cctx, cl)) + // A private class variable can be accessed only in the class where + // it is defined. + if (*name == '_' && cctx->ctx_ufunc->uf_class != cl) { semsg(_(e_cannot_access_private_member_str), m->ocm_name); return FAIL; @@ -447,7 +456,7 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type) *arg = name_end; return generate_CLASSMEMBER(cctx, TRUE, cl, idx); } - semsg(_(e_class_member_not_found_str), name); + member_not_found_msg(cl, VAR_CLASS, name, len); } return FAIL; @@ -762,9 +771,17 @@ compile_load( } else if ((idx = cctx_class_member_idx(cctx, *arg, len, &cl)) >= 0) { - // Referencing a class member without the class name. Infer - // the class from the def function context. - res = generate_CLASSMEMBER(cctx, TRUE, cl, idx); + // Referencing a class variable without the class name. + // A class variable can be referenced without the class name + // only in the class where the function is defined. + if (cctx->ctx_ufunc->uf_defclass == cl) + res = generate_CLASSMEMBER(cctx, TRUE, cl, idx); + else + { + semsg(_(e_class_member_str_accessible_only_inside_class_str), + name, cl->class_name); + res = FAIL; + } } else { @@ -1130,12 +1147,23 @@ compile_call( } else if ((mi = cctx_class_method_idx(cctx, name, varlen, &cl)) >= 0) { - // Class method invocation without the class name. The - // generate_CALL() function expects the class type at the top of - // the stack. So push the class type to the stack. - push_type_stack(cctx, &t_class); - res = generate_CALL(cctx, cl->class_class_functions[mi], NULL, 0, - type, argcount); + // Class method invocation without the class name. + // A class method can be referenced without the class name only in + // the class where the function is defined. + if (cctx->ctx_ufunc->uf_defclass == cl) + { + // The generate_CALL() function expects the class type at the + // top of the stack. So push the class type to the stack. + push_type_stack(cctx, &t_class); + res = generate_CALL(cctx, cl->class_class_functions[mi], NULL, + 0, type, argcount); + } + else + { + semsg(_(e_class_member_str_accessible_only_inside_class_str), + name, cl->class_name); + res = FAIL; + } goto theend; } }