patch 9.0.2169: Vim9: builtin funcs may accept a non-value
Problem: Vim9: builtin funcs may accept a non-value
Solution: Restrict builtin functions that accept `type`
This PR finishes off detection and prevention of using a type as a
value. It takes care of builtin functions. However there are some
builtin functions, that need to be able to handle types as well as
non-args: instanceof(), type(), typename(), string().
A "bit", FE_X, is added to funcentry_T; when set, the builtin function
can handle a type (class or type-alias) in addition to a value.
Noteworthy change: Discovered that in compile_call() the builtin add()
is compiled inline instead of calling the builtin. Had to add a check
there.
closes: #13688
Signed-off-by: Ernie Rael <errael@raelity.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim
index 1267936..9af0d07 100644
--- a/src/testdir/test_vim9_builtin.vim
+++ b/src/testdir/test_vim9_builtin.vim
@@ -5048,4 +5048,153 @@
v9.CheckDefExecAndScriptFailure(['writefile(["a"], "")'], 'E482: Can''t create file <empty>')
enddef
+def Test_passing_type_to_builtin()
+ # type, typename, string, instanceof are allowed type argument
+ var lines =<< trim END
+ vim9script
+ class C
+ endclass
+ type T = number
+ type U = C
+ var x: any
+ x = type(C)
+ x = type(T)
+ x = typename(C)
+ x = typename(T)
+ x = string(C)
+ x = string(T)
+ x = instanceof(C.new(), U, C)
+ END
+ v9.CheckScriptSuccess(lines)
+
+ # check argument to add at script level
+ # Note: add() is special cased in compile_call in vim9expr
+ lines =<< trim END
+ vim9script
+ class C
+ endclass
+ add([], C)
+ END
+ v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value')
+
+ # check argument to add in :def
+ lines =<< trim END
+ vim9script
+ class C
+ endclass
+ def F()
+ add([], C)
+ enddef
+ F()
+ END
+ v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value')
+
+ # check member call argument to add at script level
+ lines =<< trim END
+ vim9script
+ class C
+ endclass
+ []->add(C)
+ END
+ v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value')
+
+ # check member call argument to add in :def
+ lines =<< trim END
+ vim9script
+ class C
+ endclass
+ def F()
+ []->add(C)
+ enddef
+ F()
+ END
+ v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value')
+
+ # Try "empty()" builtin
+ # check argument to empty at script level
+ lines =<< trim END
+ vim9script
+ class C
+ endclass
+ empty(C)
+ END
+ v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value')
+
+ # check argument to empty in :def
+ lines =<< trim END
+ vim9script
+ class C
+ endclass
+ def F()
+ empty(C)
+ enddef
+ F()
+ END
+ v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value')
+
+ # check member call argument to empty at script level
+ lines =<< trim END
+ vim9script
+ class C
+ endclass
+ C->empty()
+ END
+ v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value')
+
+ # check member call argument to empty in :def
+ lines =<< trim END
+ vim9script
+ class C
+ endclass
+ def F()
+ C->empty()
+ enddef
+ F()
+ END
+ v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value')
+
+ # Try "abs()" builtin
+ # check argument to abs at script level
+ lines =<< trim END
+ vim9script
+ class C
+ endclass
+ abs(C)
+ END
+ v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value')
+
+ # check argument to abs in :def
+ lines =<< trim END
+ vim9script
+ class C
+ endclass
+ def F()
+ abs(C)
+ enddef
+ F()
+ END
+ v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value')
+
+ # check member call argument to abs at script level
+ lines =<< trim END
+ vim9script
+ class C
+ endclass
+ C->abs()
+ END
+ v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value')
+
+ # check member call argument to abs in :def
+ lines =<< trim END
+ vim9script
+ class C
+ endclass
+ def F()
+ C->abs()
+ enddef
+ F()
+ END
+ v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value')
+enddef
+
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
diff --git a/src/testdir/test_vim9_typealias.vim b/src/testdir/test_vim9_typealias.vim
index e735e79..4f88768 100644
--- a/src/testdir/test_vim9_typealias.vim
+++ b/src/testdir/test_vim9_typealias.vim
@@ -296,7 +296,7 @@
type A = list<string>
var x = json_encode(A)
END
- v9.CheckSourceFailure(lines, 'E1161: Cannot json encode a typealias', 3)
+ v9.CheckSourceFailure(lines, 'E1403: Type alias "A" cannot be used as a value', 3)
# Comparing type alias with a number (script level)
lines =<< trim END
@@ -452,9 +452,9 @@
var lines =<< trim END
vim9script
type A = list<func>
- assert_equal(0, empty(A))
+ var x = empty(A)
END
- v9.CheckScriptSuccess(lines)
+ v9.CheckScriptFailure(lines, 'E1403: Type alias "A" cannot be used as a value', 3)
# Using a type alias with len()
lines =<< trim END
@@ -462,7 +462,7 @@
type A = list<func>
var x = len(A)
END
- v9.CheckScriptFailure(lines, 'E701: Invalid type for len()', 3)
+ v9.CheckScriptFailure(lines, 'E1403: Type alias "A" cannot be used as a value', 3)
# Using a type alias with len()
lines =<< trim END
@@ -473,7 +473,7 @@
enddef
Foo()
END
- v9.CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected list<any> but got typealias', 1)
+ v9.CheckScriptFailure(lines, 'E1407: Cannot use a Typealias as a variable or value', 1)
# Using a type alias with eval()
lines =<< trim END
@@ -780,4 +780,134 @@
v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value', 1)
enddef
+def Test_passing_typealias_to_builtin()
+ # type, typename, string, instanceof are allowed type argument
+ var lines =<< trim END
+ vim9script
+ type T = number
+ var x: any
+ x = type(T)
+ x = typename(T)
+ x = string(T)
+ END
+ v9.CheckScriptSuccess(lines)
+
+ # check argument to add at script level
+ # Note: add() is special cased in compile_call in vim9expr
+ lines =<< trim END
+ vim9script
+ type T = number
+ add([], T)
+ END
+ v9.CheckScriptFailure(lines, 'E1403: Type alias "T" cannot be used as a value')
+
+ # check argument to add in :def
+ lines =<< trim END
+ vim9script
+ type T = number
+ def F()
+ add([], T)
+ enddef
+ F()
+ END
+ v9.CheckScriptFailure(lines, 'E1407: Cannot use a Typealias as a variable or value')
+
+ # check member call argument to add at script level
+ lines =<< trim END
+ vim9script
+ type T = number
+ []->add(T)
+ END
+ v9.CheckScriptFailure(lines, 'E1403: Type alias "T" cannot be used as a value')
+
+ # check member call argument to add in :def
+ lines =<< trim END
+ vim9script
+ type T = number
+ def F()
+ []->add(T)
+ enddef
+ F()
+ END
+ v9.CheckScriptFailure(lines, 'E1407: Cannot use a Typealias as a variable or value')
+
+ # Try "empty()" builtin
+ # check argument to empty at script level
+ lines =<< trim END
+ vim9script
+ type T = number
+ empty(T)
+ END
+ v9.CheckScriptFailure(lines, 'E1403: Type alias "T" cannot be used as a value')
+
+ # check argument to empty in :def
+ lines =<< trim END
+ vim9script
+ type T = number
+ def F()
+ empty(T)
+ enddef
+ F()
+ END
+ v9.CheckScriptFailure(lines, 'E1407: Cannot use a Typealias as a variable or value')
+
+ # check member call argument to empty at script level
+ lines =<< trim END
+ vim9script
+ type T = number
+ T->empty()
+ END
+ v9.CheckScriptFailure(lines, 'E1403: Type alias "T" cannot be used as a value')
+
+ # check member call argument to empty in :def
+ lines =<< trim END
+ vim9script
+ type T = number
+ def F()
+ T->empty()
+ enddef
+ F()
+ END
+ v9.CheckScriptFailure(lines, 'E1407: Cannot use a Typealias as a variable or value')
+
+ # Try "abs()" builtin
+ # check argument to abs at script level
+ lines =<< trim END
+ vim9script
+ type T = number
+ abs(T)
+ END
+ v9.CheckScriptFailure(lines, 'E1403: Type alias "T" cannot be used as a value')
+
+ # check argument to abs in :def
+ lines =<< trim END
+ vim9script
+ type T = number
+ def F()
+ abs(T)
+ enddef
+ F()
+ END
+ v9.CheckScriptFailure(lines, 'E1407: Cannot use a Typealias as a variable or value')
+
+ # check member call argument to abs at script level
+ lines =<< trim END
+ vim9script
+ type T = number
+ T->abs()
+ END
+ v9.CheckScriptFailure(lines, 'E1403: Type alias "T" cannot be used as a value')
+
+ # check member call argument to abs in :def
+ lines =<< trim END
+ vim9script
+ type T = number
+ def F()
+ T->abs()
+ enddef
+ F()
+ END
+ v9.CheckScriptFailure(lines, 'E1407: Cannot use a Typealias as a variable or value')
+enddef
+
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker