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>
diff --git a/src/errors.h b/src/errors.h
index 0d53fa8..6184037 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -3411,16 +3411,14 @@
 	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 @@
 	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 @@
 	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 @@
 	INIT(= "E1408: Internal error: ap_types or ap_types[idx] is NULL: %d: %s");
 EXTERN char e_interface_static_direct_access_str[]
 	INIT(= N_("E1409: Cannot directly access interface \"%s\" static member \"%s\""));
-// E1371 - E1399 unused
+// E1376 - E1399 unused
diff --git a/src/eval.c b/src/eval.c
index dd7b8d8..5235469 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1596,10 +1596,7 @@
 
 		if (lp->ll_valtype == NULL)
 		{
-		    if (v_type == VAR_OBJECT)
-			semsg(_(e_object_member_not_found_str), key);
-		    else
-			semsg(_(e_class_member_not_found_str), key);
+		    member_not_found_msg(cl, v_type, key, p - key);
 		    return NULL;
 		}
 	    }
diff --git a/src/proto/vim9class.pro b/src/proto/vim9class.pro
index a61c40f..1448f19 100644
--- a/src/proto/vim9class.pro
+++ b/src/proto/vim9class.pro
@@ -26,6 +26,8 @@
 void object_created(object_T *obj);
 void object_cleared(object_T *obj);
 int object_free_nonref(int copyID);
+void method_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len);
+void member_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len);
 void f_instanceof(typval_T *argvars, typval_T *rettv);
 int class_instance_of(class_T *cl, class_T *other_cl);
 /* vim: set ft=c : */
diff --git a/src/structs.h b/src/structs.h
index 9214096..4a82c82 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1791,8 +1791,11 @@
     def_status_T uf_def_status; // UF_NOT_COMPILED, UF_TO_BE_COMPILED, etc.
     int		uf_dfunc_idx;	// only valid if uf_def_status is UF_COMPILED
 
-    class_T	*uf_class;	// for object method and constructor; does not
-				// count for class_refcount
+    class_T	*uf_class;	// for class/object method and constructor;
+				// does not count for class_refcount.
+				// class of the object which is invoking this
+				// function.
+    class_T	*uf_defclass;	// class where this function is defined.
 
     garray_T	uf_args;	// arguments, including optional arguments
     garray_T	uf_def_args;	// default argument expressions
diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim
index be4eb2e..1796f5f 100644
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -8,56 +8,56 @@
       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 @@
         this
       endclass
   END
-  v9.CheckScriptFailure(lines, 'E1317:')
+  v9.CheckSourceFailure(lines, 'E1317:')
 
   lines =<< trim END
       vim9script
@@ -73,7 +73,7 @@
         this.
       endclass
   END
-  v9.CheckScriptFailure(lines, 'E1317:')
+  v9.CheckSourceFailure(lines, 'E1317:')
 
   lines =<< trim END
       vim9script
@@ -81,7 +81,7 @@
         this .count
       endclass
   END
-  v9.CheckScriptFailure(lines, 'E1317:')
+  v9.CheckSourceFailure(lines, 'E1317:')
 
   lines =<< trim END
       vim9script
@@ -89,7 +89,7 @@
         this. count
       endclass
   END
-  v9.CheckScriptFailure(lines, 'E1317:')
+  v9.CheckSourceFailure(lines, 'E1317:')
 
   lines =<< trim END
       vim9script
@@ -98,7 +98,7 @@
         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 @@
         this.count
       endclass
   END
-  v9.CheckScriptFailure(lines, 'E1022:')
+  v9.CheckSourceFailure(lines, 'E1022:')
 
   lines =<< trim END
       vim9script
@@ -117,7 +117,7 @@
       endclass
       var obj = Something.new()
   END
-  v9.CheckScriptFailure(lines, 'E1089:')
+  v9.CheckSourceFailure(lines, 'E1089:')
 
   lines =<< trim END
       vim9script
@@ -125,7 +125,7 @@
         this.count : number
       endclass
   END
-  v9.CheckScriptFailure(lines, 'E1059:')
+  v9.CheckSourceFailure(lines, 'E1059:')
 
   lines =<< trim END
       vim9script
@@ -133,7 +133,7 @@
         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 @@
       #{
     endclass
   END
-  v9.CheckScriptFailure(lines, 'E1170:')
+  v9.CheckSourceFailure(lines, 'E1170:')
 
   lines =<< trim END
       vim9script
@@ -171,7 +171,7 @@
       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 @@
     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 @@
     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 @@
     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 @@
   endclass
   var a = A.new()
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 enddef
 
 def Test_class_defined_twice()
@@ -232,7 +232,7 @@
       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 @@
       var buffers = BufferList.new()
       echo buffers.Current()
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 enddef
 
 def Test_using_null_class()
@@ -276,7 +276,7 @@
         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 @@
         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 @@
       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 @@
       enddef
       Func()
   END
-  v9.CheckScriptFailure(lines, 'E1360:')
+  v9.CheckSourceFailure(lines, 'E1360:')
 
   lines =<< trim END
       vim9script
@@ -337,7 +337,7 @@
       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 @@
       enddef
       Func()
   END
-  v9.CheckScriptFailure(lines, 'E1363:')
+  v9.CheckSourceFailure(lines, 'E1363:')
 enddef
 
 def Test_null_object_assign_compare()
@@ -396,7 +396,7 @@
     o2 = null_object
     assert_true(o2 == null)
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 enddef
 
 def Test_class_member_initializer()
@@ -432,7 +432,7 @@
             '\d\+ RETURN object.*',
             instr)
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 enddef
 
 def Test_member_any_used_as_object()
@@ -456,7 +456,7 @@
       F(outer_obj)
       assert_equal(1, inner_obj.value)
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 
   lines =<< trim END
       vim9script
@@ -482,7 +482,51 @@
 
       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 @@
       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 @@
       AddToFoo(f)
       assert_equal(23, f.x)
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 enddef
 
 def Test_list_of_objects()
@@ -559,7 +603,7 @@
       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 @@
 
       Foo()
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 enddef
 
 def Test_class_default_new()
@@ -606,7 +650,7 @@
       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 @@
       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 @@
 
       var missing = Person.new()
   END
-  v9.CheckScriptFailure(lines, 'E119:')
+  v9.CheckSourceFailure(lines, 'E119:')
 enddef
 
 
@@ -677,7 +721,7 @@
 
       Check()
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 
   lines =<< trim END
       vim9script
@@ -699,7 +743,7 @@
 
       Check()
   END
-  v9.CheckScriptFailure(lines, 'E1013:')
+  v9.CheckSourceFailure(lines, 'E1013:')
 
   lines =<< trim END
       vim9script
@@ -721,7 +765,7 @@
 
       Check()
   END
-  v9.CheckScriptFailure(lines, 'E1013:')
+  v9.CheckSourceFailure(lines, 'E1013:')
 enddef
 
 def Test_class_object_member_inits()
@@ -738,7 +782,7 @@
       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 @@
         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 @@
       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 @@
     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 @@
       trip.three = 33
       assert_equal(33, trip.three)
 
-      assert_fails('trip.four = 4', 'E1334')
+      assert_fails('trip.four = 4', 'E1326')
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 
   # Test for a public member variable name beginning with an underscore
   lines =<< trim END
@@ -818,7 +863,7 @@
       public this._val = 10
     endclass
   END
-  v9.CheckScriptFailure(lines, 'E1332:')
+  v9.CheckSourceFailure(lines, 'E1332:')
 
   lines =<< trim END
       vim9script
@@ -854,7 +899,7 @@
       enddef
       CheckCar()
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 
   lines =<< trim END
       vim9script
@@ -870,7 +915,7 @@
       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 @@
             .Add(2)
             .x
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 
   # Test for "public" cannot be abbreviated
   lines =<< trim END
@@ -905,7 +950,7 @@
       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 @@
       public val = 1
     endclass
   END
-  v9.CheckScriptFailure(lines, 'E1331:')
+  v9.CheckSourceFailure(lines, 'E1331:')
 
-  # Test for "static" cannot be abbreviated
+  # Modify a instance variable using the class name in the script context
   lines =<< trim END
     vim9script
-    class Something
-      stat this.val = 1
+    class A
+      public this.val = 1
     endclass
+    A.val = 1
   END
-  v9.CheckScriptFailure(lines, 'E1065:')
+  v9.CheckSourceFailure(lines, 'E1376: Object member "val" accessible only using class "A" object')
 
-  # Test for "static" cannot be followed by "this".
+  # Read a instance variable using the class name in the script context
   lines =<< trim END
     vim9script
-    class Something
-      static this.val = 1
+    class A
+      public this.val = 1
     endclass
+    var i = A.val
   END
-  v9.CheckScriptFailure(lines, 'E1368: Static cannot be followed by "this" in a member name')
+  v9.CheckSourceFailure(lines, 'E1376: Object member "val" accessible only using class "A" object')
+
+  # Modify a instance variable using the class name in a def function
+  lines =<< trim END
+    vim9script
+    class A
+      public this.val = 1
+    endclass
+    def T()
+      A.val = 1
+    enddef
+    T()
+  END
+  v9.CheckSourceFailure(lines, 'E1376: Object member "val" accessible only using class "A" object')
+
+  # Read a instance variable using the class name in a def function
+  lines =<< trim END
+    vim9script
+    class A
+      public this.val = 1
+    endclass
+    def T()
+      var i = A.val
+    enddef
+    T()
+  END
+  v9.CheckSourceFailure(lines, 'E1376: Object member "val" accessible only using class "A" object')
 
   # Access from child class extending a class:
   lines =<< trim END
@@ -941,10 +1014,6 @@
         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 @@
           this.rw_obj_var = 0
           x = this._priv_obj_var
           this._priv_obj_var = 0
+        enddef
+      endclass
 
-          x = ro_class_var
-          ro_class_var = 0
-          x = rw_class_var
-          rw_class_var = 0
-          x = _priv_class_var
-          _priv_class_var = 0
+      var b = B.new()
+      b.Foo()
+  END
+  v9.CheckSourceSuccess(lines)
+enddef
 
-          x = A.ro_class_var
-          A.ro_class_var = 0
-          x = A.rw_class_var
-          A.rw_class_var = 0
-          x = A._priv_class_var
+" Test for class variable access
+def Test_class_variable_access()
+  # Test for "static" cannot be abbreviated
+  var lines =<< trim END
+    vim9script
+    class Something
+      stat this.val = 1
+    endclass
+  END
+  v9.CheckSourceFailure(lines, 'E1065:')
+
+  # Test for "static" cannot be followed by "this".
+  lines =<< trim END
+    vim9script
+    class Something
+      static this.val = 1
+    endclass
+  END
+  v9.CheckSourceFailure(lines, 'E1368: Static cannot be followed by "this" in a member name')
+
+  # Test for "static" cannot be followed by "public".
+  lines =<< trim END
+    vim9script
+    class Something
+      static public val = 1
+    endclass
+  END
+  v9.CheckSourceFailure(lines, 'E1022: Type or initialization required')
+
+  # A readonly class variable cannot be modified from a child class
+  lines =<< trim END
+      vim9script
+      class A
+        static ro_class_var = 40
+      endclass
+
+      class B extends A
+        def Foo()
+          A.ro_class_var = 50
+        enddef
+      endclass
+
+      var b = B.new()
+      b.Foo()
+  END
+  v9.CheckSourceFailure(lines, 'E46: Cannot change read-only variable "ro_class_var"')
+
+  # A private class variable cannot be accessed from a child class
+  lines =<< trim END
+      vim9script
+      class A
+        static _priv_class_var = 60
+      endclass
+
+      class B extends A
+        def Foo()
+          var i = A._priv_class_var
+        enddef
+      endclass
+
+      var b = B.new()
+      b.Foo()
+  END
+  v9.CheckSourceFailure(lines, 'E1333: Cannot access private member: _priv_class_var')
+
+  # A private class variable cannot be modified from a child class
+  lines =<< trim END
+      vim9script
+      class A
+        static _priv_class_var = 60
+      endclass
+
+      class B extends A
+        def Foo()
           A._priv_class_var = 0
         enddef
       endclass
@@ -976,7 +1115,37 @@
       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 @@
       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 @@
           '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 @@
 
       t = m
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 
   lines =<< trim END
       vim9script
@@ -1056,7 +1225,7 @@
 
       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 @@
       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 @@
 
       echo Fn(Num.new(4))
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 enddef
 
 def Test_class_member()
@@ -1116,7 +1285,7 @@
       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 @@
       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 @@
         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 @@
       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 @@
       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 @@
       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 @@
       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 @@
       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 @@
       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 @@
     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 @@
     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 @@
     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 @@
     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 @@
       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 @@
     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 @@
       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 @@
       view = MyView.new()
       test_garbagecollect_now()
   END
-  call v9.CheckScriptSuccess(lines)
+  call v9.CheckSourceSuccess(lines)
 endfunc
 
 " Test interface garbage collection
@@ -1432,7 +1601,7 @@
     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 @@
       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 @@
       aaa
     endclass
   END
-  v9.CheckScriptFailure(lines, 'E1318:')
+  v9.CheckSourceFailure(lines, 'E1318:')
 enddef
 
 def Test_class_defcompile()
@@ -1485,7 +1654,7 @@
 
       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 @@
 
       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 @@
 
       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 @@
     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 @@
     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 @@
     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 @@
       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 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 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 @@
   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 @@
         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 GetCount(): number
       endinterface
   END
-  v9.CheckScriptFailure(lines, 'E1344:')
+  v9.CheckSourceFailure(lines, 'E1344:')
 
   lines =<< trim END
       vim9script
@@ -1631,7 +1800,7 @@
         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 @@
         enddef
       endclass
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 
   lines =<< trim END
       vim9script
@@ -1712,7 +1881,7 @@
         static count: number
       endclass
   END
-  v9.CheckScriptFailure(lines, 'E1350:')
+  v9.CheckSourceFailure(lines, 'E1350:')
 
   lines =<< trim END
       vim9script
@@ -1725,7 +1894,7 @@
         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 @@
         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 @@
         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 @@
 
       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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     class B implements A;
     endclass
   END
-  v9.CheckScriptFailure(lines, 'E1315:')
+  v9.CheckSourceFailure(lines, 'E1315:')
 
   lines =<< trim END
       vim9script
@@ -1871,7 +2040,7 @@
         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 @@
         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 @@
         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 @@
         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 @@
 
     class B extends A
         def new()
-            svar1 = 21
-            svar2 = 22
             this.mvar1 = 121
             this.mvar2 = 122
         enddef
@@ -1948,8 +2115,6 @@
 
     class C extends B
         def new()
-            svar1 = 31
-            svar2 = 32
             this.mvar1 = 131
             this.mvar2 = 132
         enddef
@@ -1967,7 +2132,7 @@
     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 @@
         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 @@
     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 @@
     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 @@
     assert_equal('child', g:result)
     unlet g:result
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 
   lines =<< trim END
     vim9script
@@ -2099,7 +2258,7 @@
     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 @@
     assert_equal('child/resource', g:result)
     unlet g:result
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 
   lines =<< trim END
     vim9script
@@ -2152,7 +2311,7 @@
     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 @@
 
       defcompile
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 enddef
 
 def Test_class_used_as_type()
@@ -2187,7 +2346,7 @@
       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 @@
       var hx = p
       assert_equal(2, hx.x)
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 
   lines =<< trim END
       vim9script
@@ -2219,7 +2378,7 @@
       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 @@
       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 @@
       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 @@
         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 @@
         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 @@
         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 @@
       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 @@
         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 @@
       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 @@
       enddef
       echo ToString()
   END
-  v9.CheckScriptFailure(lines, 'E1357:')
+  v9.CheckSourceFailure(lines, 'E1357:')
 
   lines =<< trim END
       vim9script
@@ -2363,7 +2522,7 @@
       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 @@
       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 @@
       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 @@
       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 @@
     class B extends A"
     endclass
   END
-  v9.CheckScriptFailure(lines, 'E1315:')
+  v9.CheckSourceFailure(lines, 'E1315:')
 enddef
 
 def Test_using_base_class()
@@ -2470,7 +2629,7 @@
     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 @@
     var obj = Child.new()
     assert_equal(true, obj.success)
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 enddef
 
 
@@ -2536,7 +2695,7 @@
       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 @@
       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 @@
       enddef
     endclass
   END
-  v9.CheckScriptFailure(lines, 'E1359:')
+  v9.CheckSourceFailure(lines, 'E1359:')
 enddef
 
 def Test_closure_in_class()
@@ -2583,7 +2742,7 @@
       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 @@
       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 @@
       })
       assert_equal('entered/called/exited', g:result)
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
   unlet g:result
 
   lines =<< trim END
@@ -2672,7 +2831,7 @@
       })
       assert_equal('entered-child/called/exited-child', g:result)
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
   unlet g:result
 enddef
 
@@ -2712,7 +2871,7 @@
 
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
 
     F()
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 enddef
 
 " Test the return type of the new() constructor
@@ -3006,7 +3165,7 @@
     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 @@
     enddef
     F()
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 
   # new() uses "any" return type and returns "this"
   lines =<< trim END
@@ -3054,7 +3213,7 @@
       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 @@
     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 @@
     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 @@
     G()
     assert_equal(2, current.val)
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 enddef
 
 " Test for a private object method
@@ -3152,7 +3311,7 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
       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 @@
     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 @@
     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 @@
     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 @@
       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 @@
     var t = C.new()
     Baz(t)
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 
   lines =<< trim END
     vim9script
@@ -3772,7 +3931,7 @@
 
     Baz()
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 enddef
 
 def Test_static_inheritence()
@@ -3797,21 +3956,17 @@
 
     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 @@
     assert_equal(102, ob.AccessObject())
     assert_equal(103, oc.AccessObject())
 
-    assert_equal(444, oc.AccessPrivateStaticThroughClassName())
+    assert_fails('echo oc.AccessPrivateStaticThroughClassName()', 'E1333: Cannot access private member: _svar')
 
     # verify object properly resolves to correct static
     assert_equal(1, oa.AccessStaticThroughObject())
-    assert_equal(2, ob.AccessStaticThroughObject())
-    assert_equal(3, oc.AccessStaticThroughObject())
+    assert_equal(1, ob.AccessStaticThroughObject())
+    assert_equal(1, oc.AccessStaticThroughObject())
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 enddef
 
 " Test for declaring duplicate object and class members
@@ -3843,7 +3998,7 @@
       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 @@
       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 @@
       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 @@
       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 @@
       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 @@
       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 @@
       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 @@
     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 @@
       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 @@
       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 @@
       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 @@
       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 @@
       public static svar: number
     endclass
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 enddef
 
 def Test_interface_static_member_access()
@@ -4058,7 +4157,7 @@
     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 @@
     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 @@
     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 @@
     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 @@
 
     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 @@
 
     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 @@
 
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
       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 @@
       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 @@
     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 @@
     enddef
     T()
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 enddef
 
 " Test for accessing a class member variable using an object
@@ -4337,7 +4435,7 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
 "     T1(c)
 "     T2(c)
 "   END
-"   v9.CheckScriptSuccess(lines)
+"   v9.CheckSourceSuccess(lines)
 " enddef
 
 " Test for abstract methods
@@ -4498,7 +4596,7 @@
     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 @@
     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 @@
     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 @@
     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 @@
       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 @@
       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 @@
     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 @@
       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 @@
     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 @@
     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 @@
     a.Bar()
     T()
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckSourceSuccess(lines)
 
   # script context
   lines =<< trim END
@@ -4652,7 +4774,7 @@
     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 @@
     enddef
     T()
   END
-  v9.CheckScriptFailure(lines, 'E1325: Method not found on class "A": Foo()')
+  v9.CheckSourceFailure(lines, 'E1375: Class member "Foo" accessible only using class "A"')
+enddef
+
+def Test_class_variable()
+  var lines =<< trim END
+    vim9script
+
+    class A
+      public static val: number = 10
+      static def ClassFunc()
+        assert_equal(10, val)
+      enddef
+      def ObjFunc()
+        assert_equal(10, val)
+      enddef
+    endclass
+
+    class B extends A
+    endclass
+
+    assert_equal(10, A.val)
+    A.ClassFunc()
+    var a = A.new()
+    a.ObjFunc()
+    var b = B.new()
+    b.ObjFunc()
+
+    def T1(a1: A)
+      a1.ObjFunc()
+      A.ClassFunc()
+    enddef
+    T1(b)
+
+    A.val = 20
+    assert_equal(20, A.val)
+  END
+  v9.CheckSourceSuccess(lines)
+
+  # Modifying a parent class variable from a child class method
+  lines =<< trim END
+    vim9script
+
+    class A
+      static val: number = 10
+    endclass
+
+    class B extends A
+      static def ClassFunc()
+        val = 20
+      enddef
+    endclass
+    B.ClassFunc()
+  END
+  v9.CheckSourceFailure(lines, 'E1374: Class member "val" accessible only inside class "A"')
+
+  # Reading a parent class variable from a child class method
+  lines =<< trim END
+    vim9script
+
+    class A
+      static val: number = 10
+    endclass
+
+    class B extends A
+      static def ClassFunc()
+        var i = val
+      enddef
+    endclass
+    B.ClassFunc()
+  END
+  v9.CheckSourceFailure(lines, 'E1374: Class member "val" accessible only inside class "A"')
+
+  # Modifying a parent class variable from a child object method
+  lines =<< trim END
+    vim9script
+
+    class A
+      static val: number = 10
+    endclass
+
+    class B extends A
+      def ObjFunc()
+        val = 20
+      enddef
+    endclass
+    var b = B.new()
+    b.ObjFunc()
+  END
+  v9.CheckSourceFailure(lines, 'E1374: Class member "val" accessible only inside class "A"')
+
+  # Reading a parent class variable from a child object method
+  lines =<< trim END
+    vim9script
+
+    class A
+      static val: number = 10
+    endclass
+
+    class B extends A
+      def ObjFunc()
+        var i = val
+      enddef
+    endclass
+    var b = B.new()
+    b.ObjFunc()
+  END
+  v9.CheckSourceFailure(lines, 'E1374: Class member "val" accessible only inside class "A"')
+
+  # Modifying a class variable using an object at script level
+  lines =<< trim END
+    vim9script
+
+    class A
+      static val: number = 10
+    endclass
+    var a = A.new()
+    a.val = 20
+  END
+  v9.CheckSourceFailure(lines, 'E1375: Class member "val" accessible only using class "A"')
+
+  # Reading a class variable using an object at script level
+  lines =<< trim END
+    vim9script
+
+    class A
+      static val: number = 10
+    endclass
+    var a = A.new()
+    var i = a.val
+  END
+  v9.CheckSourceFailure(lines, 'E1375: Class member "val" accessible only using class "A"')
+
+  # Modifying a class variable using an object at function level
+  lines =<< trim END
+    vim9script
+
+    class A
+      static val: number = 10
+    endclass
+
+    def T()
+      var a = A.new()
+      a.val = 20
+    enddef
+    T()
+  END
+  v9.CheckSourceFailure(lines, 'E1374: Class member "val" accessible only inside class "A"')
+
+  # Reading a class variable using an object at function level
+  lines =<< trim END
+    vim9script
+
+    class A
+      static val: number = 10
+    endclass
+    def T()
+      var a = A.new()
+      var i = a.val
+    enddef
+    T()
+  END
+  v9.CheckSourceFailure(lines, 'E1375: Class member "val" accessible only using class "A"')
+enddef
+
+" Test for using a duplicate class method and class variable in a child class
+def Test_dup_class_member()
+  # duplicate class variable, class method and overridden object method
+  var lines =<< trim END
+    vim9script
+    class A
+      static sval = 100
+      static def Check()
+        assert_equal(100, sval)
+      enddef
+      def GetVal(): number
+        return sval
+      enddef
+    endclass
+
+    class B extends A
+      static sval = 200
+      static def Check()
+        assert_equal(200, sval)
+      enddef
+      def GetVal(): number
+        return sval
+      enddef
+    endclass
+
+    def T1(aa: A): number
+      return aa.GetVal()
+    enddef
+
+    def T2(bb: B): number
+      return bb.GetVal()
+    enddef
+
+    assert_equal(100, A.sval)
+    assert_equal(200, B.sval)
+    var a = A.new()
+    assert_equal(100, a.GetVal())
+    var b = B.new()
+    assert_equal(200, b.GetVal())
+    assert_equal(200, T1(b))
+    assert_equal(200, T2(b))
+  END
+  v9.CheckSourceSuccess(lines)
+
+  # duplicate class variable and class method
+  lines =<< trim END
+    vim9script
+    class A
+      static sval = 100
+      static def Check()
+        assert_equal(100, sval)
+      enddef
+      def GetVal(): number
+        return sval
+      enddef
+    endclass
+
+    class B extends A
+      static sval = 200
+      static def Check()
+        assert_equal(200, sval)
+      enddef
+    endclass
+
+    def T1(aa: A): number
+      return aa.GetVal()
+    enddef
+
+    def T2(bb: B): number
+      return bb.GetVal()
+    enddef
+
+    assert_equal(100, A.sval)
+    assert_equal(200, B.sval)
+    var a = A.new()
+    assert_equal(100, a.GetVal())
+    var b = B.new()
+    assert_equal(100, b.GetVal())
+    assert_equal(100, T1(b))
+    assert_equal(100, T2(b))
+  END
+  v9.CheckSourceSuccess(lines)
+enddef
+
+" Test for calling an instance method using the class
+def Test_instance_method_call_using_class()
+  # Invoke an object method using a class in script context
+  var lines =<< trim END
+    vim9script
+    class A
+      def Foo()
+        echo "foo"
+      enddef
+    endclass
+    A.Foo()
+  END
+  v9.CheckSourceFailure(lines, 'E1376: Object member "Foo" accessible only using class "A" object')
+
+  # Invoke an object method using a class in def function context
+  lines =<< trim END
+    vim9script
+    class A
+      def Foo()
+        echo "foo"
+      enddef
+    endclass
+    def T()
+      A.Foo()
+    enddef
+    T()
+  END
+  v9.CheckSourceFailure(lines, 'E1376: Object member "Foo" accessible only using class "A" object')
+enddef
+
+" Test for duplicate class method and instance method
+def Test_dup_classmethod_objmethod()
+  # Duplicate instance method
+  var lines =<< trim END
+    vim9script
+    class A
+      static def Foo()
+      enddef
+      def Foo()
+      enddef
+    endclass
+  END
+  v9.CheckSourceFailure(lines, 'E1355: Duplicate function: Foo')
+
+  # Duplicate private instance method
+  lines =<< trim END
+    vim9script
+    class A
+      static def Foo()
+      enddef
+      def _Foo()
+      enddef
+    endclass
+  END
+  v9.CheckSourceFailure(lines, 'E1355: Duplicate function: _Foo')
+
+  # Duplicate class method
+  lines =<< trim END
+    vim9script
+    class A
+      def Foo()
+      enddef
+      static def Foo()
+      enddef
+    endclass
+  END
+  v9.CheckSourceFailure(lines, 'E1355: Duplicate function: Foo')
+
+  # Duplicate private class method
+  lines =<< trim END
+    vim9script
+    class A
+      def Foo()
+      enddef
+      static def _Foo()
+      enddef
+    endclass
+  END
+  v9.CheckSourceFailure(lines, 'E1355: Duplicate function: _Foo')
+
+  # Duplicate private class and object method
+  lines =<< trim END
+    vim9script
+    class A
+      def _Foo()
+      enddef
+      static def _Foo()
+      enddef
+    endclass
+  END
+  v9.CheckSourceFailure(lines, 'E1355: Duplicate function: _Foo')
+enddef
+
+" Test for an instance method access level comparison with parent instance
+" methods.
+def Test_instance_method_access_level()
+  # Private method in subclass
+  var lines =<< trim END
+    vim9script
+    class A
+      def Foo()
+      enddef
+    endclass
+    class B extends A
+    endclass
+    class C extends B
+      def _Foo()
+      enddef
+    endclass
+  END
+  v9.CheckSourceFailure(lines, 'E1378: Access level of method "_Foo" is different in class "A"')
+
+  # Public method in subclass
+  lines =<< trim END
+    vim9script
+    class A
+      def _Foo()
+      enddef
+    endclass
+    class B extends A
+    endclass
+    class C extends B
+      def Foo()
+      enddef
+    endclass
+  END
+  v9.CheckSourceFailure(lines, 'E1378: Access level of method "Foo" is different in class "A"')
+enddef
+
+def Test_extend_empty_class()
+  var lines =<< trim END
+    vim9script
+    class A
+    endclass
+    class B extends A
+    endclass
+    class C extends B
+      public static rw_class_var = 1
+      public this.rw_obj_var = 2
+      static def ClassMethod(): number
+        return 3
+      enddef
+      def ObjMethod(): number
+        return 4
+      enddef
+    endclass
+    assert_equal(1, C.rw_class_var)
+    assert_equal(3, C.ClassMethod())
+    var c = C.new()
+    assert_equal(2, c.rw_obj_var)
+    assert_equal(4, c.ObjMethod())
+  END
+  v9.CheckSourceSuccess(lines)
 enddef
 
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
diff --git a/src/testdir/vim9.vim b/src/testdir/vim9.vim
index 5877a79..782809b 100644
--- a/src/testdir/vim9.vim
+++ b/src/testdir/vim9.vim
@@ -110,6 +110,40 @@
   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)
diff --git a/src/version.c b/src/version.c
index aaa50da..ba4be27 100644
--- a/src/version.c
+++ b/src/version.c
@@ -700,6 +700,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1898,
+/**/
     1897,
 /**/
     1896,
diff --git a/src/vim9class.c b/src/vim9class.c
index ccc3818..bf7d632 100644
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -322,63 +322,109 @@
 }
 
 /*
- * Check whether a class/object member variable in "classmembers_gap" /
- * "objmembers_gap" is a duplicate of a member in any of the extended parent
- * class lineage.  Returns TRUE if there are no duplicates.
+ * Check method names in the parent class lineage to make sure the access is
+ * the same for overridden methods.
+ */
+    static int
+validate_extends_methods(
+    garray_T	*objmethods_gap,
+    class_T	*extends_cl)
+{
+    class_T	*super = extends_cl;
+    int		method_count = objmethods_gap->ga_len;
+    ufunc_T	**cl_fp = (ufunc_T **)(objmethods_gap->ga_data);
+
+    while (super != NULL)
+    {
+	int extends_method_count = super->class_obj_method_count_child;
+	if (extends_method_count == 0)
+	{
+	    super = super->class_extends;
+	    continue;
+	}
+
+	ufunc_T **extends_methods = super->class_obj_methods;
+
+	for (int i = 0; i < extends_method_count; i++)
+	{
+	    char_u  *pstr = extends_methods[i]->uf_name;
+	    int	    extends_private = (*pstr == '_');
+	    if (extends_private)
+		pstr++;
+
+	    for (int j = 0; j < method_count; j++)
+	    {
+		char_u  *qstr = cl_fp[j]->uf_name;
+		int	priv_method = (*qstr == '_');
+		if (priv_method)
+		    qstr++;
+		if (STRCMP(pstr, qstr) == 0 && priv_method != extends_private)
+		{
+		    // Method access is different between the super class and
+		    // the subclass
+		    semsg(_(e_method_str_of_class_str_has_different_access),
+			    cl_fp[j]->uf_name, super->class_name);
+		    return FALSE;
+		}
+	    }
+	}
+	super = super->class_extends;
+    }
+
+    return TRUE;
+}
+
+/*
+ * Check whether a object member variable in "objmembers_gap" is a duplicate of
+ * a member in any of the extended parent class lineage.  Returns TRUE if there
+ * are no duplicates.
  */
     static int
 validate_extends_members(
-    garray_T	*classmembers_gap,
     garray_T	*objmembers_gap,
     class_T	*extends_cl)
 {
-    for (int loop = 1; loop <= 2; ++loop)
-    {
-	// loop == 1: check class members
-	// loop == 2: check object members
-	int member_count = loop == 1 ? classmembers_gap->ga_len
-						: objmembers_gap->ga_len;
-	if (member_count == 0)
-	    continue;
-	ocmember_T *members = (ocmember_T *)(loop == 1
-						? classmembers_gap->ga_data
-						: objmembers_gap->ga_data);
+    // loop == 1: check class members
+    // loop == 2: check object members
+    int member_count = objmembers_gap->ga_len;
+    if (member_count == 0)
+	return TRUE;
 
-	// Validate each member variable
-	for (int c_i = 0; c_i < member_count; c_i++)
-	{
-	    class_T	*p_cl = extends_cl;
-	    ocmember_T	*c_m = members + c_i;
-	    char_u	*pstr = (*c_m->ocm_name == '_')
+    ocmember_T *members = (ocmember_T *)(objmembers_gap->ga_data);
+
+    // Validate each member variable
+    for (int c_i = 0; c_i < member_count; c_i++)
+    {
+	class_T	    *p_cl = extends_cl;
+	ocmember_T  *c_m = members + c_i;
+	char_u	    *pstr = (*c_m->ocm_name == '_')
 					? c_m->ocm_name + 1 : c_m->ocm_name;
 
-	    // Check in all the parent classes in the lineage
-	    while (p_cl != NULL)
+	// Check in all the parent classes in the lineage
+	while (p_cl != NULL)
+	{
+	    int p_member_count = p_cl->class_obj_member_count;
+	    if (p_member_count == 0)
 	    {
-		int p_member_count = loop == 1
-					? p_cl->class_class_member_count
-					: p_cl->class_obj_member_count;
-		if (p_member_count == 0)
-		    continue;
-		ocmember_T *p_members = (loop == 1
-					? p_cl->class_class_members
-					: p_cl->class_obj_members);
-
-		// Compare against all the members in the parent class
-		for (int p_i = 0; p_i < p_member_count; p_i++)
-		{
-		    ocmember_T	*p_m = p_members + p_i;
-		    char_u	*qstr = (*p_m->ocm_name == '_')
-					? p_m->ocm_name + 1 : p_m->ocm_name;
-		    if (STRCMP(pstr, qstr) == 0)
-		    {
-			semsg(_(e_duplicate_member_str), c_m->ocm_name);
-			return FALSE;
-		    }
-		}
-
 		p_cl = p_cl->class_extends;
+		continue;
 	    }
+	    ocmember_T *p_members = p_cl->class_obj_members;
+
+	    // Compare against all the members in the parent class
+	    for (int p_i = 0; p_i < p_member_count; p_i++)
+	    {
+		ocmember_T	*p_m = p_members + p_i;
+		char_u	*qstr = (*p_m->ocm_name == '_')
+		    ? p_m->ocm_name + 1 : p_m->ocm_name;
+		if (STRCMP(pstr, qstr) == 0)
+		{
+		    semsg(_(e_duplicate_member_str), c_m->ocm_name);
+		    return FALSE;
+		}
+	    }
+
+	    p_cl = p_cl->class_extends;
 	}
     }
 
@@ -391,7 +437,7 @@
  * 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 @@
  * 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 @@
 	    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 @@
 
 	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 @@
 	{
 	    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 @@
 		    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 @@
 	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 @@
 	    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 @@
 								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 @@
 	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 @@
 	    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 @@
 	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 @@
 }
 
 /*
- * 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 @@
 }
 
 /*
+ * Echo a class or object method not found message.
+ */
+    void
+method_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len)
+{
+    char_u *method_name = vim_strnsave(name, len);
+    if ((v_type == VAR_OBJECT)
+	    && (class_method_idx(cl, name, len) >= 0))
+    {
+	// If this is a class method, then give a different error
+	if (*name == '_')
+	    semsg(_(e_cannot_access_private_method_str), method_name);
+	else
+	    semsg(_(e_class_member_str_accessible_only_using_class_str),
+		    method_name, cl->class_name);
+    }
+    else if ((v_type == VAR_CLASS)
+	    && (object_method_idx(cl, name, len) >= 0))
+    {
+	// If this is an object method, then give a different error
+	if (*name == '_')
+	    semsg(_(e_cannot_access_private_method_str), method_name);
+	else
+	    semsg(_(e_object_member_str_accessible_only_using_object_str),
+		    method_name, cl->class_name);
+    }
+    else
+	semsg(_(e_method_not_found_on_class_str_str), cl->class_name,
+		method_name);
+    vim_free(method_name);
+}
+
+/*
+ * Echo a class or object member not found message.
+ */
+    void
+member_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len)
+{
+    char_u *varname = len ? vim_strnsave(name, len) : vim_strsave(name);
+
+    if (v_type == VAR_OBJECT)
+    {
+	if (class_member_idx(cl, name, len) >= 0)
+	    semsg(_(e_class_member_str_accessible_only_using_class_str),
+		    varname, cl->class_name);
+	else
+	    semsg(_(e_member_not_found_on_object_str_str), cl->class_name,
+		    varname);
+    }
+    else
+    {
+	if (object_member_idx(cl, name, len) >= 0)
+	    semsg(_(e_object_member_str_accessible_only_using_object_str),
+		    varname, cl->class_name);
+	else
+	    semsg(_(e_class_member_str_not_found_in_class_str),
+		    varname, cl->class_name);
+    }
+    vim_free(varname);
+}
+
+/*
  * Return TRUE when the class "cl", its base class or one of the implemented
  * interfaces matches the class "other_cl".
  */
diff --git a/src/vim9compile.c b/src/vim9compile.c
index cc4aa46..7de1b62 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -332,24 +332,42 @@
 }
 
 /*
- * 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 @@
 }
 
 /*
- * 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 @@
     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 @@
 	}
 	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 @@
 		}
 	    }
 	    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 @@
 
 	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 @@
 	    // 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 @@
 	    }
 	    // If it is private member variable, then accessing it outside the
 	    // class is not allowed.
-	    if ((m->ocm_access != VIM_ACCESS_ALL) && !inside_class(cctx, cl))
+	    // If it is a read only class variable, then it can be modified
+	    // only inside the class where it is defined.
+	    if ((m->ocm_access != VIM_ACCESS_ALL) &&
+		    ((is_object && !inside_class(cctx, cl))
+		     || (!is_object && cctx->ctx_ufunc->uf_class != cl)))
 	    {
 		char *msg = (m->ocm_access == VIM_ACCESS_PRIVATE)
 				? e_cannot_access_private_member_str
diff --git a/src/vim9execute.c b/src/vim9execute.c
index f8e2676..7c61ff4 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -2172,8 +2172,7 @@
 	    {
 		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 @@
 	    }
 	    else
 	    {
-		semsg(_(e_member_not_found_on_object_str_str),
-						       cl->class_name, member);
+		member_not_found_msg(cl, VAR_OBJECT, member, 0);
 		status = FAIL;
 	    }
 	}
diff --git a/src/vim9expr.c b/src/vim9expr.c
index 120a606..a158f31 100644
--- a/src/vim9expr.c
+++ b/src/vim9expr.c
@@ -367,12 +367,19 @@
 	}
 	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 @@
 	    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 @@
 			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 @@
 	    *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 @@
 	    }
 	    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 @@
 	}
 	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;
 	}
     }