diff src/testdir/test_vim9_class.vim @ 33951:45a50fd59a73 v9.0.2170

patch 9.0.2170: Vim9: no support for const/final class/objects vars Commit: https://github.com/vim/vim/commit/e5437c542709b77ade084f96e60d84d4e847e6d3 Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Sat Dec 16 14:11:19 2023 +0100 patch 9.0.2170: Vim9: no support for const/final class/objects vars Problem: Vim9: no support for const/final class/objects vars Solution: Support final and const object and class variables closes: #13655 Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
author Christian Brabandt <cb@256bit.org>
date Sat, 16 Dec 2023 14:15:05 +0100
parents 3bba09502b8d
children 6d33f47b71b8
line wrap: on
line diff
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -9051,4 +9051,612 @@ def Test_compile_many_def_functions_in_f
   assert_equal(0, v:shell_error)
 enddef
 
+" Test for 'final' class and object variables
+def Test_final_class_object_variable()
+  # Test for changing a final object variable from an object function
+  var lines =<< trim END
+    vim9script
+    class A
+      final foo: string = "abc"
+      def Foo()
+        this.foo = "def"
+      enddef
+    endclass
+    defcompile A.Foo
+  END
+  v9.CheckSourceFailure(lines, 'E1409: Cannot change read-only variable "foo" in class "A"', 1)
+
+  # Test for changing a final object variable from the 'new' function
+  lines =<< trim END
+    vim9script
+    class A
+      final s1: string
+      final s2: string
+      def new(this.s1)
+        this.s2 = 'def'
+      enddef
+    endclass
+    var a = A.new('abc')
+    assert_equal('abc', a.s1)
+    assert_equal('def', a.s2)
+  END
+  v9.CheckSourceSuccess(lines)
+
+  # Test for a final class variable
+  lines =<< trim END
+    vim9script
+    class A
+      static final s1: string = "abc"
+    endclass
+    assert_equal('abc', A.s1)
+  END
+  v9.CheckSourceSuccess(lines)
+
+  # Test for changing a final class variable from a class function
+  lines =<< trim END
+    vim9script
+    class A
+      static final s1: string = "abc"
+      static def Foo()
+        s1 = "def"
+      enddef
+    endclass
+    A.Foo()
+  END
+  v9.CheckSourceFailure(lines, 'E1409: Cannot change read-only variable "s1" in class "A"', 1)
+
+  # Test for changing a public final class variable at script level
+  lines =<< trim END
+    vim9script
+    class A
+      public static final s1: string = "abc"
+    endclass
+    assert_equal('abc', A.s1)
+    A.s1 = 'def'
+  END
+  v9.CheckSourceFailure(lines, 'E1409: Cannot change read-only variable "s1" in class "A"', 6)
+
+  # Test for changing a public final class variable from a class function
+  lines =<< trim END
+    vim9script
+    class A
+      public static final s1: string = "abc"
+      static def Foo()
+        s1 = "def"
+      enddef
+    endclass
+    A.Foo()
+  END
+  v9.CheckSourceFailure(lines, 'E1409: Cannot change read-only variable "s1" in class "A"', 1)
+
+  # Test for changing a public final class variable from a function
+  lines =<< trim END
+    vim9script
+    class A
+      public static final s1: string = "abc"
+    endclass
+    def Foo()
+      A.s1 = 'def'
+    enddef
+    defcompile
+  END
+  v9.CheckSourceFailure(lines, 'E1409: Cannot change read-only variable "s1" in class "A"', 1)
+
+  # Test for using a final variable of composite type
+  lines =<< trim END
+    vim9script
+    class A
+      public final l: list<number>
+      def new()
+        this.l = [1, 2]
+      enddef
+      def Foo()
+        this.l[0] = 3
+        this.l->add(4)
+      enddef
+    endclass
+    var a = A.new()
+    assert_equal([1, 2], a.l)
+    a.Foo()
+    assert_equal([3, 2, 4], a.l)
+  END
+  v9.CheckSourceSuccess(lines)
+
+  # Test for changing a final variable of composite type from another object
+  # function
+  lines =<< trim END
+    vim9script
+    class A
+      public final l: list<number> = [1, 2]
+      def Foo()
+        this.l = [3, 4]
+      enddef
+    endclass
+    var a = A.new()
+    a.Foo()
+  END
+  v9.CheckSourceFailure(lines, 'E1409: Cannot change read-only variable "l" in class "A"', 1)
+
+  # Test for modifying a final variable of composite type at script level
+  lines =<< trim END
+    vim9script
+    class A
+      public final l: list<number> = [1, 2]
+    endclass
+    var a = A.new()
+    a.l[0] = 3
+    a.l->add(4)
+    assert_equal([3, 2, 4], a.l)
+  END
+  v9.CheckSourceSuccess(lines)
+
+  # Test for modifying a final variable of composite type from a function
+  lines =<< trim END
+    vim9script
+    class A
+      public final l: list<number> = [1, 2]
+    endclass
+    def Foo()
+      var a = A.new()
+      a.l[0] = 3
+      a.l->add(4)
+      assert_equal([3, 2, 4], a.l)
+    enddef
+    Foo()
+  END
+  v9.CheckSourceSuccess(lines)
+
+  # Test for modifying a final variable of composite type from another object
+  # function
+  lines =<< trim END
+    vim9script
+    class A
+      public final l: list<number> = [1, 2]
+      def Foo()
+        this.l[0] = 3
+        this.l->add(4)
+      enddef
+    endclass
+    var a = A.new()
+    a.Foo()
+    assert_equal([3, 2, 4], a.l)
+  END
+  v9.CheckSourceSuccess(lines)
+
+  # Test for assigning a new value to a final variable of composite type at
+  # script level
+  lines =<< trim END
+    vim9script
+    class A
+      public final l: list<number> = [1, 2]
+    endclass
+    var a = A.new()
+    a.l = [3, 4]
+  END
+  v9.CheckSourceFailure(lines, 'E1409: Cannot change read-only variable "l" in class "A"', 6)
+
+  # Test for assigning a new value to a final variable of composite type from
+  # another object function
+  lines =<< trim END
+    vim9script
+    class A
+      public final l: list<number> = [1, 2]
+      def Foo()
+        this.l = [3, 4]
+      enddef
+    endclass
+    var a = A.new()
+    a.Foo()
+  END
+  v9.CheckSourceFailure(lines, 'E1409: Cannot change read-only variable "l" in class "A"', 1)
+
+  # Test for assigning a new value to a final variable of composite type from
+  # another function
+  lines =<< trim END
+    vim9script
+    class A
+      public final l: list<number> = [1, 2]
+    endclass
+    def Foo()
+      var a = A.new()
+      a.l = [3, 4]
+    enddef
+    Foo()
+  END
+  v9.CheckSourceFailure(lines, 'E1409: Cannot change read-only variable "l" in class "A"', 2)
+
+  # Error case: Use 'final' with just a variable name
+  lines =<< trim END
+    vim9script
+    class A
+      final foo
+    endclass
+    var a = A.new()
+  END
+  v9.CheckSourceFailure(lines, 'E1022: Type or initialization required', 3)
+
+  # Error case: Use 'final' followed by 'public'
+  lines =<< trim END
+    vim9script
+    class A
+      final public foo: number
+    endclass
+    var a = A.new()
+  END
+  v9.CheckSourceFailure(lines, 'E1022: Type or initialization required', 3)
+
+  # Error case: Use 'final' followed by 'static'
+  lines =<< trim END
+    vim9script
+    class A
+      final static foo: number
+    endclass
+    var a = A.new()
+  END
+  v9.CheckSourceFailure(lines, 'E1022: Type or initialization required', 3)
+
+  # Error case: 'final' cannot be used in an interface
+  lines =<< trim END
+    vim9script
+    interface A
+      final foo: number = 10
+    endinterface
+  END
+  v9.CheckSourceFailure(lines, 'E1408: Final variable not supported in an interface', 3)
+
+  # Error case: 'final' not supported for an object method
+  lines =<< trim END
+    vim9script
+    class A
+      final def Foo()
+      enddef
+    endclass
+  END
+  v9.CheckSourceFailure(lines, 'E1022: Type or initialization required', 3)
+
+  # Error case: 'final' not supported for a class method
+  lines =<< trim END
+    vim9script
+    class A
+      static final def Foo()
+      enddef
+    endclass
+  END
+  v9.CheckSourceFailure(lines, 'E1022: Type or initialization required', 3)
+enddef
+
+" Test for 'const' class and object variables
+def Test_const_class_object_variable()
+  # Test for changing a const object variable from an object function
+  var lines =<< trim END
+    vim9script
+    class A
+      const foo: string = "abc"
+      def Foo()
+        this.foo = "def"
+      enddef
+    endclass
+    defcompile A.Foo
+  END
+  v9.CheckSourceFailure(lines, 'E1409: Cannot change read-only variable "foo" in class "A"', 1)
+
+  # Test for changing a const object variable from the 'new' function
+  lines =<< trim END
+    vim9script
+    class A
+      const s1: string
+      const s2: string
+      def new(this.s1)
+        this.s2 = 'def'
+      enddef
+    endclass
+    var a = A.new('abc')
+    assert_equal('abc', a.s1)
+    assert_equal('def', a.s2)
+  END
+  v9.CheckSourceSuccess(lines)
+
+  # Test for changing a const object variable from an object method called from
+  # the 'new' function
+  lines =<< trim END
+    vim9script
+    class A
+      const s1: string = 'abc'
+      def new()
+        this.ChangeStr()
+      enddef
+      def ChangeStr()
+        this.s1 = 'def'
+      enddef
+    endclass
+    var a = A.new()
+  END
+  v9.CheckSourceFailure(lines, 'E1409: Cannot change read-only variable "s1" in class "A"', 1)
+
+  # Test for a const class variable
+  lines =<< trim END
+    vim9script
+    class A
+      static const s1: string = "abc"
+    endclass
+    assert_equal('abc', A.s1)
+  END
+  v9.CheckSourceSuccess(lines)
+
+  # Test for changing a const class variable from a class function
+  lines =<< trim END
+    vim9script
+    class A
+      static const s1: string = "abc"
+      static def Foo()
+        s1 = "def"
+      enddef
+    endclass
+    A.Foo()
+  END
+  v9.CheckSourceFailure(lines, 'E1409: Cannot change read-only variable "s1" in class "A"', 1)
+
+  # Test for changing a public const class variable at script level
+  lines =<< trim END
+    vim9script
+    class A
+      public static const s1: string = "abc"
+    endclass
+    assert_equal('abc', A.s1)
+    A.s1 = 'def'
+  END
+  v9.CheckSourceFailure(lines, 'E1409: Cannot change read-only variable "s1" in class "A"', 6)
+
+  # Test for changing a public const class variable from a class function
+  lines =<< trim END
+    vim9script
+    class A
+      public static const s1: string = "abc"
+      static def Foo()
+        s1 = "def"
+      enddef
+    endclass
+    A.Foo()
+  END
+  v9.CheckSourceFailure(lines, 'E1409: Cannot change read-only variable "s1" in class "A"', 1)
+
+  # Test for changing a public const class variable from a function
+  lines =<< trim END
+    vim9script
+    class A
+      public static const s1: string = "abc"
+    endclass
+    def Foo()
+      A.s1 = 'def'
+    enddef
+    defcompile
+  END
+  v9.CheckSourceFailure(lines, 'E1409: Cannot change read-only variable "s1" in class "A"', 1)
+
+  # Test for changing a const List item from an object function
+  lines =<< trim END
+    vim9script
+    class A
+      public const l: list<number>
+      def new()
+        this.l = [1, 2]
+      enddef
+      def Foo()
+        this.l[0] = 3
+      enddef
+    endclass
+    var a = A.new()
+    assert_equal([1, 2], a.l)
+    a.Foo()
+  END
+  v9.CheckSourceFailure(lines, 'E1119: Cannot change locked list item', 1)
+
+  # Test for adding a value to a const List from an object function
+  lines =<< trim END
+    vim9script
+    class A
+      public const l: list<number>
+      def new()
+        this.l = [1, 2]
+      enddef
+      def Foo()
+        this.l->add(3)
+      enddef
+    endclass
+    var a = A.new()
+    a.Foo()
+  END
+  v9.CheckSourceFailure(lines, 'E741: Value is locked: add() argument', 1)
+
+  # Test for reassigning a const List from an object function
+  lines =<< trim END
+    vim9script
+    class A
+      public const l: list<number> = [1, 2]
+      def Foo()
+        this.l = [3, 4]
+      enddef
+    endclass
+    var a = A.new()
+    a.Foo()
+  END
+  v9.CheckSourceFailure(lines, 'E1409: Cannot change read-only variable "l" in class "A"', 1)
+
+  # Test for changing a const List item at script level
+  lines =<< trim END
+    vim9script
+    class A
+      public const l: list<number> = [1, 2]
+    endclass
+    var a = A.new()
+    a.l[0] = 3
+  END
+  v9.CheckSourceFailure(lines, 'E741: Value is locked:',  6)
+
+  # Test for adding a value to a const List item at script level
+  lines =<< trim END
+    vim9script
+    class A
+      public const l: list<number> = [1, 2]
+    endclass
+    var a = A.new()
+    a.l->add(4)
+  END
+  v9.CheckSourceFailure(lines, 'E741: Value is locked:', 6)
+
+  # Test for changing a const List item from a function
+  lines =<< trim END
+    vim9script
+    class A
+      public const l: list<number> = [1, 2]
+    endclass
+    def Foo()
+      var a = A.new()
+      a.l[0] = 3
+    enddef
+    Foo()
+  END
+  v9.CheckSourceFailure(lines, 'E1119: Cannot change locked list item', 2)
+
+  # Test for adding a value to a const List item from a function
+  lines =<< trim END
+    vim9script
+    class A
+      public const l: list<number> = [1, 2]
+    endclass
+    def Foo()
+      var a = A.new()
+      a.l->add(4)
+    enddef
+    Foo()
+  END
+  v9.CheckSourceFailure(lines, 'E741: Value is locked: add() argument', 2)
+
+  # Test for changing a const List item from an object method
+  lines =<< trim END
+    vim9script
+    class A
+      public const l: list<number> = [1, 2]
+      def Foo()
+        this.l[0] = 3
+      enddef
+    endclass
+    var a = A.new()
+    a.Foo()
+  END
+  v9.CheckSourceFailure(lines, 'E1119: Cannot change locked list item', 1)
+
+  # Test for adding a value to a const List item from an object method
+  lines =<< trim END
+    vim9script
+    class A
+      public const l: list<number> = [1, 2]
+      def Foo()
+        this.l->add(4)
+      enddef
+    endclass
+    var a = A.new()
+    a.Foo()
+  END
+  v9.CheckSourceFailure(lines, 'E741: Value is locked: add() argument', 1)
+
+  # Test for reassigning a const List object variable at script level
+  lines =<< trim END
+    vim9script
+    class A
+      public const l: list<number> = [1, 2]
+    endclass
+    var a = A.new()
+    a.l = [3, 4]
+  END
+  v9.CheckSourceFailure(lines, 'E1409: Cannot change read-only variable "l" in class "A"', 6)
+
+  # Test for reassigning a const List object variable from an object method
+  lines =<< trim END
+    vim9script
+    class A
+      public const l: list<number> = [1, 2]
+      def Foo()
+        this.l = [3, 4]
+      enddef
+    endclass
+    var a = A.new()
+    a.Foo()
+  END
+  v9.CheckSourceFailure(lines, 'E1409: Cannot change read-only variable "l" in class "A"', 1)
+
+  # Test for reassigning a const List object variable from another function
+  lines =<< trim END
+    vim9script
+    class A
+      public const l: list<number> = [1, 2]
+    endclass
+    def Foo()
+      var a = A.new()
+      a.l = [3, 4]
+    enddef
+    Foo()
+  END
+  v9.CheckSourceFailure(lines, 'E1409: Cannot change read-only variable "l" in class "A"', 2)
+
+  # Error case: Use 'const' with just a variable name
+  lines =<< trim END
+    vim9script
+    class A
+      const foo
+    endclass
+    var a = A.new()
+  END
+  v9.CheckSourceFailure(lines, 'E1022: Type or initialization required', 3)
+
+  # Error case: Use 'const' followed by 'public'
+  lines =<< trim END
+    vim9script
+    class A
+      const public foo: number
+    endclass
+    var a = A.new()
+  END
+  v9.CheckSourceFailure(lines, 'E1022: Type or initialization required', 3)
+
+  # Error case: Use 'const' followed by 'static'
+  lines =<< trim END
+    vim9script
+    class A
+      const static foo: number
+    endclass
+    var a = A.new()
+  END
+  v9.CheckSourceFailure(lines, 'E1022: Type or initialization required', 3)
+
+  # Error case: 'const' cannot be used in an interface
+  lines =<< trim END
+    vim9script
+    interface A
+      const foo: number = 10
+    endinterface
+  END
+  v9.CheckSourceFailure(lines, 'E1410: Const variable not supported in an interface', 3)
+
+  # Error case: 'const' not supported for an object method
+  lines =<< trim END
+    vim9script
+    class A
+      const def Foo()
+      enddef
+    endclass
+  END
+  v9.CheckSourceFailure(lines, 'E1022: Type or initialization required', 3)
+
+  # Error case: 'const' not supported for a class method
+  lines =<< trim END
+    vim9script
+    class A
+      static const def Foo()
+      enddef
+    endclass
+  END
+  v9.CheckSourceFailure(lines, 'E1022: Type or initialization required', 3)
+enddef
+
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker