changeset 33260:aba1fa2b7d1e v9.0.1898

patch 9.0.1898: Vim9: restrict access to static vars Commit: https://github.com/vim/vim/commit/c30a90d9b2c029f794cea502f6b824f71e4876dd Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Fri Sep 15 20:14:55 2023 +0200 patch 9.0.1898: Vim9: restrict access to static vars Problem: Vim9: restrict access to static vars and methods Solution: Class members are accesible only from the class where they are defined. Based on the #13004 discussion, the following changes are made: 1) Static variables and methods are accessible only using the class name and inside the class where they are defined. 2) Static variables and methods can be used without the class name in the class where they are defined. 3) Static variables of a super class are not copied to the sub class. 4) A sub class can declare a class variable with the same name as the super class. 5) When a method or member is found during compilation, use more specific error messages. This aligns the Vim9 class variable/method implementation with the Dart implementation. Also while at it, ignore duplicate class and object methods. The access level of an object method can however be changed in a subclass. For the tests, use the new CheckSourceFailure() function instead of the CheckScriptFailure() function in the tests. closes: #13086 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
author Christian Brabandt <cb@256bit.org>
date Fri, 15 Sep 2023 20:30:05 +0200
parents cf3186a6807f
children cc83932e459d
files src/errors.h src/eval.c src/proto/vim9class.pro src/structs.h src/testdir/test_vim9_class.vim src/testdir/vim9.vim src/version.c src/vim9class.c src/vim9compile.c src/vim9execute.c src/vim9expr.c
diffstat 11 files changed, 1257 insertions(+), 495 deletions(-) [+]
line wrap: on
line diff
--- a/src/errors.h
+++ b/src/errors.h
@@ -3411,16 +3411,14 @@ EXTERN char e_public_member_name_cannot_
 	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_meth
 	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_concret
 	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
--- 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;
 		}
 	    }
--- 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 : */
--- 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
--- 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<TextPosition>', typename(TextPosition))
       assert_equal('object<TextPosition>', 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> = [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')
-  END
-  v9.CheckScriptSuccess(lines)
+      assert_fails('trip.four = 4', 'E1326')
+  END
+  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:')
-
-  # Test for "static" cannot be abbreviated
+  v9.CheckSourceFailure(lines, 'E1331:')
+
+  # Modify a instance variable using the class name in the script context
+  lines =<< trim END
+    vim9script
+    class A
+      public this.val = 1
+    endclass
+    A.val = 1
+  END
+  v9.CheckSourceFailure(lines, 'E1376: Object member "val" accessible only using class "A" object')
+
+  # Read a instance variable using the class name in the script context
   lines =<< trim END
     vim9script
-    class Something
-      stat this.val = 1
-    endclass
-  END
-  v9.CheckScriptFailure(lines, 'E1065:')
-
-  # Test for "static" cannot be followed by "this".
+    class A
+      public this.val = 1
+    endclass
+    var i = A.val
+  END
+  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 Something
-      static this.val = 1
-    endclass
-  END
-  v9.CheckScriptFailure(lines, 'E1368: Static cannot be followed by "this" in a member name')
+    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
-
-          x = ro_class_var
-          ro_class_var = 0
-          x = rw_class_var
-          rw_class_var = 0
-          x = _priv_class_var
-          _priv_class_var = 0
-
-          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
+        enddef
+      endclass
+
+      var b = B.new()
+      b.Foo()
+  END
+  v9.CheckSourceSuccess(lines)
+enddef
+
+" 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<One> but got object<Two>')
+  v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected object<One> but got object<Two>')
 
   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<A> but got string')
+  v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected object<A> 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<number>): bool')
+  v9.CheckSourceFailure(lines, 'E1407: Method "IsEven": type mismatch, expected func(number): bool but got func(number, ...list<number>): 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<Point> but got string')
+  v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected object<Point> 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 <stack> 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<C>', 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_i
     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())
-  END
-  v9.CheckScriptSuccess(lines)
+    assert_equal(1, ob.AccessStaticThroughObject())
+    assert_equal(1, oc.AccessStaticThroughObject())
+  END
+  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_cl
 
     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_c
     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_c
     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_c
     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_c
     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_c
     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_c
     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_f
     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_fu
     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_obj
     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_obj
     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_obj
     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_obj
     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_obj
     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<number> but got func(number, string): list<string>')
+  v9.CheckSourceFailure(lines, 'E1407: Method "Foo": type mismatch, expected func(string, number): list<number> but got func(number, string): list<string>')
 
   # 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
--- a/src/testdir/vim9.vim
+++ b/src/testdir/vim9.vim
@@ -110,6 +110,40 @@ export def CheckScriptSuccess(lines: lis
   endtry
 enddef
 
+# :source a list of "lines" and check whether it fails with "error"
+export def CheckSourceFailure(lines: list<string>, 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<string>, errors: list<string>, 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<string>)
+  new
+  setline(1, lines)
+  try
+    :source
+  finally
+    bw!
+  endtry
+enddef
+
 export def CheckDefAndScriptSuccess(lines: list<string>)
   CheckDefSuccess(lines)
   CheckScriptSuccess(['vim9script'] + lines)
--- a/src/version.c
+++ b/src/version.c
@@ -700,6 +700,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1898,
+/**/
     1897,
 /**/
     1896,
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -322,63 +322,109 @@ validate_extends_class(char_u *extends_n
 }
 
 /*
- * 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 = objmembers_gap->ga_len;
+    if (member_count == 0)
+	return TRUE;
+
+    ocmember_T *members = (ocmember_T *)(objmembers_gap->ga_data);
+
+    // Validate each member variable
+    for (int c_i = 0; c_i < member_count; c_i++)
     {
-	// 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);
-
-	// 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 == '_')
+	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);
+		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++)
+	    // 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)
 		{
-		    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;
-		    }
+		    semsg(_(e_duplicate_member_str), c_m->ocm_name);
+		    return FALSE;
 		}
+	    }
 
-		p_cl = p_cl->class_extends;
-	    }
+	    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
  * 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 *
 	    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.
  */
@@ -2498,6 +2570,68 @@ object_free_nonref(int copyID)
 }
 
 /*
+ * 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".
  */
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -332,24 +332,42 @@ script_var_exists(char_u *name, size_t l
 }
 
 /*
- * 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
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -2172,8 +2172,7 @@ execute_storeindex(isn_T *iptr, ectx_T *
 	    {
 		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 *
 	    }
 	    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;
 	    }
 	}
--- a/src/vim9expr.c
+++ b/src/vim9expr.c
@@ -367,12 +367,19 @@ compile_class_object_index(cctx_T *cctx,
 	}
 	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,
 	    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,
 			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,
 	    *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;
 	}
     }