Mercurial > vim
diff src/testdir/test_vim9_script.vim @ 33678:7d9d2404a3d4 v9.0.2076
patch 9.0.2076: Vim9: No support for type aliases
Commit: https://github.com/vim/vim/commit/ec3cebbd2b6b7583d2f683f5e66345163ec122aa
Author: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Fri Oct 27 19:35:26 2023 +0200
patch 9.0.2076: Vim9: No support for type aliases
Problem: Vim9: No support for type aliases
Solution: Implement :type command
A type definition is giving a name to a type specification. This also known
type alias.
:type ListOfStrings = list<string>
The type alias can be used wherever a built-in type can be used. The type
alias name must start with an upper case character.
closes: #13407
Signed-off-by: Christian Brabandt <cb@256bit.org>
Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Fri, 27 Oct 2023 19:45:05 +0200 |
parents | 53416c49a7ab |
children | f126ffc85f7c |
line wrap: on
line diff
--- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -4722,7 +4722,7 @@ def Test_defer_after_exception() assert_equal([2, 3, 1, 4, 5, 6, 7], callTrace) END - v9.CheckScriptSuccess(lines) + v9.CheckSourceSuccess(lines) enddef " Test for multiple deferred function which throw exceptions. @@ -4780,6 +4780,384 @@ def Test_multidefer_with_exception() assert_equal('E605: Exception not caught: InnerException', v:errmsg) assert_equal([11, 9, 10, 7, 8, 5, 1, 3, 4, 12, 15, 16], callTrace) END + v9.CheckSourceSuccess(lines) +enddef + +" Test for :type command to create type aliases +def Test_typealias() + var lines =<< trim END + vim9script + type ListOfStrings = list<string> + var a: ListOfStrings = ['a', 'b'] + assert_equal(['a', 'b'], a) + def Foo(b: ListOfStrings): ListOfStrings + var c: ListOfStrings = ['c', 'd'] + assert_equal(['c', 'd'], c) + return b + enddef + assert_equal(['e', 'f'], Foo(['e', 'f'])) + assert_equal('typealias<list<string>>', typename(ListOfStrings)) + assert_equal(v:t_typealias, type(ListOfStrings)) + assert_equal('ListOfStrings', string(ListOfStrings)) + assert_equal(false, null == ListOfStrings) + END + v9.CheckSourceSuccess(lines) + + # Use :type outside a Vim9 script + lines =<< trim END + type Index = number + END + v9.CheckSourceFailure(lines, 'E1393: Type can only be defined in Vim9 script', 1) + + # Use :type without any arguments + lines =<< trim END + vim9script + type + END + v9.CheckSourceFailure(lines, 'E1397: Missing type alias name', 2) + + # Use :type with a name but no type + lines =<< trim END + vim9script + type MyType + END + v9.CheckSourceFailure(lines, "E398: Missing '=': ", 2) + + # Use :type with a name but no type following "=" + lines =<< trim END + vim9script + type MyType = + END + v9.CheckSourceFailure(lines, 'E1398: Missing type alias type', 2) + + # No space before or after "=" + lines =<< trim END + vim9script + type MyType=number + END + v9.CheckSourceFailure(lines, 'E1315: White space required after name: MyType=number', 2) + + # No space after "=" + lines =<< trim END + vim9script + type MyType =number + END + v9.CheckSourceFailure(lines, "E1069: White space required after '=': =number", 2) + + # type alias without "=" + lines =<< trim END + vim9script + type Index number + END + v9.CheckSourceFailure(lines, "E398: Missing '=': number", 2) + + # type alias for a non-existing type + lines =<< trim END + vim9script + type Index = integer + END + v9.CheckSourceFailure(lines, 'E1010: Type not recognized: integer', 2) + + # type alias starting with lower-case letter + lines =<< trim END + vim9script + type index number + END + v9.CheckSourceFailure(lines, 'E1394: Type name must start with an uppercase letter: index number', 2) + + # No white space following the alias name + lines =<< trim END + vim9script + type Index:number + END + v9.CheckSourceFailure(lines, 'E1315: White space required after name: Index:number', 2) + + # something following the type alias + lines =<< trim END + vim9script + type ListOfNums = list<number> string + END + v9.CheckSourceFailure(lines, 'E488: Trailing characters: string', 2) + + # type alias name collides with a variable name + lines =<< trim END + vim9script + var ListOfNums: number = 10 + type ListOfNums = list<number> + END + v9.CheckSourceFailure(lines, 'E1041: Redefining script item: "ListOfNums"', 3) + + # duplicate type alias name + lines =<< trim END + vim9script + type MyList = list<number> + type MyList = list<string> + END + v9.CheckSourceFailure(lines, 'E1396: Type alias "MyList" already exists', 3) + + # Sourcing a script twice (which will free script local variables) + lines =<< trim END + vim9script + class C + endclass + type AC = C + assert_equal('typealias<object<C>>', typename(AC)) + END + new + setline(1, lines) + :source + :source + bw! + + # Assigning to a type alias (script level) + lines =<< trim END + vim9script + type MyType = list<number> + MyType = [1, 2, 3] + END + v9.CheckSourceFailure(lines, 'E1395: Type alias "MyType" cannot be used as a variable', 3) + + # Assigning a type alias (def function level) + lines =<< trim END + vim9script + type A = list<string> + def Foo() + var x = A + enddef + Foo() + END + v9.CheckSourceFailure(lines, 'E1395: Type alias "A" cannot be used as a variable', 1) + + # Using type alias in an expression (script level) + lines =<< trim END + vim9script + type MyType = list<number> + assert_fails('var m = MyType', 'E1395: Type alias "MyType" cannot be used as a variable') + assert_fails('var i = MyType + 1', 'E1395: Type alias "MyType" cannot be used as a variable') + assert_fails('var f = 1.0 + MyType', 'E1395: Type alias "MyType" cannot be used as a variable') + assert_fails('MyType += 10', 'E1395: Type alias "MyType" cannot be used as a variable') + END + v9.CheckSourceSuccess(lines) + + # Using type alias in an expression (def function level) + lines =<< trim END + vim9script + type MyType = list<number> + def Foo() + var x = MyType + 1 + enddef + Foo() + END + v9.CheckSourceFailure(lines, 'E1395: Type alias "MyType" cannot be used as a variable', 1) + + # Using type alias in an expression (def function level) + lines =<< trim END + vim9script + type MyType = list<number> + def Foo() + MyType = list<string> + enddef + Foo() + END + v9.CheckSourceFailure(lines, 'E46: Cannot change read-only variable "MyType"', 1) + + # Using type alias in an expression (def function level) + lines =<< trim END + vim9script + type MyType = list<number> + def Foo() + MyType += 10 + enddef + Foo() + END + v9.CheckSourceFailure(lines, 'E46: Cannot change read-only variable "MyType"', 1) + + # Creating a typealias in a def function + lines =<< trim END + vim9script + def Foo() + var n: number = 10 + type A = list<string> + enddef + defcompile + END + v9.CheckSourceFailure(lines, 'E1399: Type can only be used in a script', 2) + + # json_encode should fail with a type alias + lines =<< trim END + vim9script + type A = list<string> + var x = json_encode(A) + END + v9.CheckSourceFailure(lines, 'E1161: Cannot json encode a typealias', 3) + + # Comparing type alias with a number (script level) + lines =<< trim END + vim9script + type A = list<string> + var n: number + var x = A == n + END + v9.CheckSourceFailure(lines, 'E1072: Cannot compare typealias with number', 4) + + # Comparing type alias with a number (def function level) + lines =<< trim END + vim9script + type A = list<string> + def Foo() + var n: number + var x = A == n + enddef + Foo() + END + v9.CheckSourceFailure(lines, 'E1395: Type alias "A" cannot be used as a variable', 2) +enddef + +" Test for exporting and importing type aliases +def Test_import_typealias() + var lines =<< trim END + vim9script + export type MyType = list<number> + END + writefile(lines, 'Xtypeexport.vim', 'D') + + lines =<< trim END + vim9script + import './Xtypeexport.vim' as A + + var myList: A.MyType = [1, 2, 3] + def Foo(l: A.MyType) + assert_equal([1, 2, 3], l) + enddef + Foo(myList) + END + v9.CheckScriptSuccess(lines) + + # Use a non existing type alias + lines =<< trim END + vim9script + import './Xtypeexport.vim' as A + + var myNum: A.SomeType = 10 + END + v9.CheckScriptFailure(lines, 'E1010: Type not recognized: A.SomeType = 10', 4) + + # Use a type alias that is not exported + lines =<< trim END + vim9script + type NewType = dict<string> + END + writefile(lines, 'Xtypeexport2.vim', 'D') + lines =<< trim END + vim9script + import './Xtypeexport2.vim' as A + + var myDict: A.NewType = {} + END + v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: NewType', 4) + + # Using the same name as an imported type alias + lines =<< trim END + vim9script + export type MyType2 = list<number> + END + writefile(lines, 'Xtypeexport3.vim', 'D') + lines =<< trim END + vim9script + import './Xtypeexport3.vim' as A + + type MyType2 = A.MyType2 + var myList1: A.MyType2 = [1, 2, 3] + var myList2: MyType2 = [4, 5, 6] + assert_equal([1, 2, 3], myList1) + assert_equal([4, 5, 6], myList2) + END + v9.CheckScriptSuccess(lines) +enddef + +" Test for using typealias as a def function argument and return type +def Test_typealias_func_argument() + var lines =<< trim END + vim9script + type A = list<number> + def Foo(l: A): A + assert_equal([1, 2], l) + return l + enddef + var x: A = [1, 2] + assert_equal([1, 2], Foo(x)) + END + v9.CheckScriptSuccess(lines) + + # passing a type alias variable to a function expecting a specific type + lines =<< trim END + vim9script + type A = list<number> + def Foo(l: list<number>) + assert_equal([1, 2], l) + enddef + var x: A = [1, 2] + Foo(x) + END + v9.CheckScriptSuccess(lines) + + # passing a type alias variable to a function expecting any + lines =<< trim END + vim9script + type A = list<number> + def Foo(l: any) + assert_equal([1, 2], l) + enddef + var x: A = [1, 2] + Foo(x) + END + v9.CheckScriptSuccess(lines) +enddef + +" Using a type alias with a builtin function +def Test_typealias_with_builtin_functions() + var lines =<< trim END + vim9script + type A = list<func> + assert_equal(0, empty(A)) + END + v9.CheckScriptSuccess(lines) + + # Using a type alias with len() + lines =<< trim END + vim9script + type A = list<func> + var x = len(A) + END + v9.CheckScriptFailure(lines, 'E701: Invalid type for len()', 3) + + # Using a type alias with eval() + lines =<< trim END + vim9script + type A = number + def Foo() + var x = eval("A") + enddef + Foo() + END + v9.CheckScriptFailure(lines, 'E1395: Type alias "A" cannot be used as a variable', 1) +enddef + +" Test for type alias refcount +def Test_typealias_refcount() + var lines =<< trim END + vim9script + type A = list<func> + assert_equal(1, test_refcount(A)) + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + type B = list<number> + var x: B = [] + assert_equal(1, test_refcount(B)) + END v9.CheckScriptSuccess(lines) enddef