Skip to content

Commit

Permalink
patch 8.2.4260: Vim9: can still use a global function without g:
Browse files Browse the repository at this point in the history
Problem:    Vim9: can still use a global function without g: at the script
            level.
Solution:   Also check for g: at the script level. (issue #9637)
  • Loading branch information
brammool committed Jan 30, 2022
1 parent 06011e1 commit 848fadd
Show file tree
Hide file tree
Showing 16 changed files with 102 additions and 54 deletions.
9 changes: 6 additions & 3 deletions src/evalvars.c
Expand Up @@ -2779,17 +2779,20 @@ eval_variable(
}
else if (in_vim9script() && (flags & EVAL_VAR_NO_FUNC) == 0)
{
int has_g_prefix = STRNCMP(name, "g:", 2) == 0;
ufunc_T *ufunc = find_func(name, FALSE);

// In Vim9 script we can get a function reference by using the
// function name.
if (ufunc != NULL)
// function name. For a global non-autoload function "g:" is
// required.
if (ufunc != NULL && (has_g_prefix
|| !func_requires_g_prefix(ufunc)))
{
found = TRUE;
if (rettv != NULL)
{
rettv->v_type = VAR_FUNC;
if (STRNCMP(name, "g:", 2) == 0)
if (has_g_prefix)
// Keep the "g:", otherwise script-local may be
// assumed.
rettv->vval.v_string = vim_strsave(name);
Expand Down
1 change: 1 addition & 0 deletions src/proto/userfunc.pro
Expand Up @@ -11,6 +11,7 @@ char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *e
ufunc_T *find_func_even_dead(char_u *name, int flags);
ufunc_T *find_func(char_u *name, int is_global);
int func_is_global(ufunc_T *ufunc);
int func_requires_g_prefix(ufunc_T *ufunc);
int func_name_refcount(char_u *name);
void func_clear_free(ufunc_T *fp, int force);
int copy_func(char_u *lambda, char_u *global, ectx_T *ectx);
Expand Down
2 changes: 1 addition & 1 deletion src/testdir/dumps/Test_popupwin_scroll_11.dump
Expand Up @@ -7,4 +7,4 @@
|7| @20|4+0#0000001#ffd7ff255| @28| +0#0000000#a8a8a8255| +0&#ffffff0@21
|8| @73
|9| @73
|:|c|a|l@1| |P|o|p|u|p|S|c|r|o|l@1|(|)| @37|1|,|1| @10|T|o|p|
|:|c|a|l@1| |g|:|P|o|p|u|p|S|c|r|o|l@1|(|)| @35|1|,|1| @10|T|o|p|
2 changes: 1 addition & 1 deletion src/testdir/dumps/Test_popupwin_scroll_12.dump
Expand Up @@ -7,4 +7,4 @@
|7| @20|l+0#0000001#ffd7ff255|o|n|g| |l|i|n|e| |l|o|n|g| |l|i|n|e| |l|o|n|g| |l|i|n|e| | +0#0000000#a8a8a8255| +0&#ffffff0@21
|8| @73
|9| @73
|:|c|a|l@1| |P|o|p|u|p|S|c|r|o|l@1|(|)| @37|1|,|1| @10|T|o|p|
|:|c|a|l@1| |g|:|P|o|p|u|p|S|c|r|o|l@1|(|)| @35|1|,|1| @10|T|o|p|
6 changes: 3 additions & 3 deletions src/testdir/test_ins_complete.vim
Expand Up @@ -1422,7 +1422,7 @@ func Test_completefunc_callback()
call assert_fails("set completefunc=funcref('abc')", "E700:")

#" set 'completefunc' to a non-existing function
set completefunc=CompleteFunc2
set completefunc=g:CompleteFunc2
call setline(1, 'five')
call assert_fails("set completefunc=function('NonExistingFunc')", 'E700:')
call assert_fails("LET &completefunc = function('NonExistingFunc')", 'E700:')
Expand Down Expand Up @@ -1679,7 +1679,7 @@ func Test_omnifunc_callback()
call assert_fails("set omnifunc=funcref('abc')", "E700:")

#" set 'omnifunc' to a non-existing function
set omnifunc=OmniFunc2
set omnifunc=g:OmniFunc2
call setline(1, 'nine')
call assert_fails("set omnifunc=function('NonExistingFunc')", 'E700:')
call assert_fails("LET &omnifunc = function('NonExistingFunc')", 'E700:')
Expand Down Expand Up @@ -1936,7 +1936,7 @@ func Test_thesaurusfunc_callback()
call assert_fails("set thesaurusfunc=funcref('abc')", "E700:")

#" set 'thesaurusfunc' to a non-existing function
set thesaurusfunc=TsrFunc2
set thesaurusfunc=g:TsrFunc2
call setline(1, 'ten')
call assert_fails("set thesaurusfunc=function('NonExistingFunc')", 'E700:')
call assert_fails("LET &thesaurusfunc = function('NonExistingFunc')", 'E700:')
Expand Down
4 changes: 2 additions & 2 deletions src/testdir/test_popupwin.vim
Expand Up @@ -2263,7 +2263,7 @@ func Test_popup_scrollbar()
\ wrap: true,
\ scrollbar: true,
\ mapping: false,
\ filter: Popup_filter,
\ filter: g:Popup_filter,
\ })
enddef

Expand Down Expand Up @@ -2328,7 +2328,7 @@ func Test_popup_scrollbar()
call VerifyScreenDump(buf, 'Test_popupwin_scroll_10', {})

" check size with non-wrapping lines
call term_sendkeys(buf, ":call PopupScroll()\<CR>")
call term_sendkeys(buf, ":call g:PopupScroll()\<CR>")
call VerifyScreenDump(buf, 'Test_popupwin_scroll_11', {})

" check size with wrapping lines
Expand Down
6 changes: 3 additions & 3 deletions src/testdir/test_vim9_assign.vim
Expand Up @@ -75,7 +75,7 @@ def Test_assignment()

# lower case name is OK for a list
var lambdaLines =<< trim END
var lambdaList: list<func> = [Test_syntax]
var lambdaList: list<func> = [g:Test_syntax]
lambdaList[0] = () => "lambda"
END
v9.CheckDefAndScriptSuccess(lambdaLines)
Expand Down Expand Up @@ -890,7 +890,7 @@ enddef

def Test_assignment_partial()
var lines =<< trim END
var Partial: func(): string = function(PartFuncBool, [true])
var Partial: func(): string = function(g:PartFuncBool, [true])
assert_equal('done', Partial())
END
v9.CheckDefAndScriptSuccess(lines)
Expand Down Expand Up @@ -1393,7 +1393,7 @@ def Test_assignment_failure()
v9.CheckDefFailure(['var name: dict <number>'], 'E1068:')
v9.CheckDefFailure(['var name: dict<number'], 'E1009:')

assert_fails('s/^/\=Mess()/n', 'E794:')
assert_fails('s/^/\=g:Mess()/n', 'E794:')
v9.CheckDefFailure(['var name: dict<number'], 'E1009:')

v9.CheckDefFailure(['w:foo: number = 10'],
Expand Down
2 changes: 1 addition & 1 deletion src/testdir/test_vim9_builtin.vim
Expand Up @@ -1303,7 +1303,7 @@ def Test_filter()
enddef

def Test_filter_wrong_dict_key_type()
assert_fails('Wrong_dict_key_type([1, v:null, 3])', 'E1013:')
assert_fails('g:Wrong_dict_key_type([1, v:null, 3])', 'E1013:')
enddef

def Test_filter_return_type()
Expand Down
2 changes: 1 addition & 1 deletion src/testdir/test_vim9_cmd.vim
Expand Up @@ -1324,7 +1324,7 @@ def Test_gdefault_not_used()
bwipe!
enddef

def g:SomeComplFunc(findstart: number, base: string): any
def s:SomeComplFunc(findstart: number, base: string): any
if findstart
return 0
else
Expand Down
12 changes: 6 additions & 6 deletions src/testdir/test_vim9_disassemble.vim
Expand Up @@ -887,23 +887,23 @@ def Test_disassemble_call_default()
enddef


def HasEval()
def s:HasEval()
if has("eval")
echo "yes"
else
echo "no"
endif
enddef

def HasNothing()
def s:HasNothing()
if has("nothing")
echo "yes"
else
echo "no"
endif
enddef

def HasSomething()
def s:HasSomething()
if has("nothing")
echo "nothing"
elseif has("something")
Expand All @@ -915,7 +915,7 @@ def HasSomething()
endif
enddef

def HasGuiRunning()
def s:HasGuiRunning()
if has("gui_running")
echo "yes"
else
Expand Down Expand Up @@ -2487,7 +2487,7 @@ def Test_debug_for()
res)
enddef

func Legacy() dict
func s:Legacy() dict
echo 'legacy'
endfunc

Expand All @@ -2501,7 +2501,7 @@ def Test_disassemble_dict_stack()
assert_match('<SNR>\d*_UseMember\_s*' ..
'var d = {func: Legacy}\_s*' ..
'\d PUSHS "func"\_s*' ..
'\d PUSHFUNC "g:Legacy"\_s*' ..
'\d PUSHFUNC "<80><fd>R\d\+_Legacy"\_s*' ..
'\d NEWDICT size 1\_s*' ..
'\d STORE $0\_s*' ..

Expand Down
23 changes: 14 additions & 9 deletions src/testdir/test_vim9_expr.vim
Expand Up @@ -61,12 +61,17 @@ def Test_expr1_trinary()
var RetThat: func = g:atrue ? RetOne : RetTwo
assert_equal(function('len'), RetThat)

var X = FuncOne
var Y = FuncTwo
var Z = g:cond ? FuncOne : FuncTwo
var X = g:FuncOne
var Y = g:FuncTwo
var Z = g:cond ? g:FuncOne : g:FuncTwo
assert_equal(123, Z(3))
END
v9.CheckDefAndScriptSuccess(lines)

lines =<< trim END
var Z = g:cond ? FuncOne : FuncTwo
END
v9.CheckDefAndScriptFailure(lines, ['E1001: Variable not found: FuncOne', 'E121: Undefined variable: FuncTwo'])
enddef

def Test_expr1_trinary_vimscript()
Expand Down Expand Up @@ -209,9 +214,9 @@ func Test_expr1_trinary_fails()

" missing argument detected even when common type is used
call v9.CheckDefAndScriptFailure([
\ 'var X = FuncOne',
\ 'var Y = FuncTwo',
\ 'var Z = g:cond ? FuncOne : FuncTwo',
\ 'var X = g:FuncOne',
\ 'var Y = g:FuncTwo',
\ 'var Z = g:cond ? g:FuncOne : g:FuncTwo',
\ 'Z()'], 'E119:', 4)
endfunc

Expand Down Expand Up @@ -2334,7 +2339,7 @@ def Test_expr8_funcref()
def Test()
var Ref = g:GlobalFunc
assert_equal('global', Ref())
Ref = GlobalFunc
Ref = g:GlobalFunc
assert_equal('global', Ref())

Ref = s:ScriptFunc
Expand Down Expand Up @@ -3083,12 +3088,12 @@ def Test_expr8_call()
v9.CheckDefAndScriptFailure(["var Ref = function('len' [1, 2])"], ['E1123:', 'E116:'], 1)
enddef

def g:ExistingGloba(): string
def g:ExistingGlobal(): string
return 'existing'
enddef

def Test_expr8_call_global()
assert_equal('existing', g:ExistingGloba())
assert_equal('existing', g:ExistingGlobal())

def g:DefinedLater(): string
return 'later'
Expand Down
28 changes: 14 additions & 14 deletions src/testdir/test_vim9_func.vim
Expand Up @@ -340,7 +340,7 @@ enddef
def Test_return_something()
g:ReturnString()->assert_equal('string')
g:ReturnNumber()->assert_equal(123)
assert_fails('ReturnGlobal()', 'E1012: Type mismatch; expected number but got string', '', 1, 'ReturnGlobal')
assert_fails('g:ReturnGlobal()', 'E1012: Type mismatch; expected number but got string', '', 1, 'ReturnGlobal')

var lines =<< trim END
vim9script
Expand Down Expand Up @@ -943,7 +943,7 @@ def Test_local_function_shadows_global()
def g:Func(): string
return 'global'
enddef
assert_equal('global', Func())
assert_equal('global', g:Func())
delfunc g:Func
END
v9.CheckScriptSuccess(lines)
Expand Down Expand Up @@ -1498,14 +1498,14 @@ enddef

def Test_func_type_varargs()
var RefDefArg: func(?string)
RefDefArg = FuncOneDefArg
RefDefArg = g:FuncOneDefArg
RefDefArg()
s:value->assert_equal('text')
RefDefArg('some')
s:value->assert_equal('some')

var RefDef2Arg: func(?number, ?string): string
RefDef2Arg = FuncTwoDefArg
RefDef2Arg = g:FuncTwoDefArg
RefDef2Arg()->assert_equal('123text')
RefDef2Arg(99)->assert_equal('99text')
RefDef2Arg(77, 'some')->assert_equal('77some')
Expand All @@ -1514,7 +1514,7 @@ def Test_func_type_varargs()
v9.CheckDefFailure(['var RefWrong: func(?string, string)'], 'E1007:')

var RefVarargs: func(...list<string>): string
RefVarargs = FuncVarargs
RefVarargs = g:FuncVarargs
RefVarargs()->assert_equal('')
RefVarargs('one')->assert_equal('one')
RefVarargs('one', 'two')->assert_equal('one,two')
Expand Down Expand Up @@ -1721,7 +1721,7 @@ enddef

def Test_error_in_nested_function()
# Error in called function requires unwinding the call stack.
assert_fails('FuncWithForwardCall()', 'E1096:', '', 1, 'FuncWithForwardCall')
assert_fails('g:FuncWithForwardCall()', 'E1096:', '', 1, 'FuncWithForwardCall')
enddef

def Test_nested_function_with_nextcmd()
Expand Down Expand Up @@ -2199,7 +2199,7 @@ def Test_func_type()
s:funcResult->assert_equal(22)

s:funcResult = 0
Ref2 = FuncOneArgRetNumber
Ref2 = g:FuncOneArgRetNumber
Ref2(13)->assert_equal(13)
s:funcResult->assert_equal(13)
enddef
Expand Down Expand Up @@ -2232,24 +2232,24 @@ def Test_func_type_part()
RefVoid = g:FuncNoArgNoRet
RefVoid = g:FuncOneArgNoRet
v9.CheckDefFailure(['var RefVoid: func: void', 'RefVoid = g:FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...) but got func(): number')
v9.CheckDefFailure(['var RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...) but got func(): string')
v9.CheckDefFailure(['var RefVoid: func: void', 'RefVoid = g:FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...) but got func(): string')

var RefAny: func(): any
RefAny = g:FuncNoArgRetNumber
RefAny = FuncNoArgRetString
RefAny = g:FuncNoArgRetString
v9.CheckDefFailure(['var RefAny: func(): any', 'RefAny = g:FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func()')
v9.CheckDefFailure(['var RefAny: func(): any', 'RefAny = g:FuncOneArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func(number)')

var RefAnyNoArgs: func: any = RefAny

var RefNr: func: number
RefNr = g:FuncNoArgRetNumber
RefNr = FuncOneArgRetNumber
RefNr = g:FuncOneArgRetNumber
v9.CheckDefFailure(['var RefNr: func: number', 'RefNr = g:FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): number but got func()')
v9.CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...): number but got func(): string')
v9.CheckDefFailure(['var RefNr: func: number', 'RefNr = g:FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...): number but got func(): string')

var RefStr: func: string
RefStr = FuncNoArgRetString
RefStr = g:FuncNoArgRetString
RefStr = FuncOneArgRetString
v9.CheckDefFailure(['var RefStr: func: string', 'RefStr = g:FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): string but got func()')
v9.CheckDefFailure(['var RefStr: func: string', 'RefStr = g:FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...): string but got func(): number')
Expand All @@ -2260,7 +2260,7 @@ def Test_func_type_fails()

v9.CheckDefFailure(['var Ref1: func()', 'Ref1 = g:FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(): number')
v9.CheckDefFailure(['var Ref1: func()', 'Ref1 = g:FuncOneArgNoRet'], 'E1012: Type mismatch; expected func() but got func(number)')
v9.CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(number): number')
v9.CheckDefFailure(['var Ref1: func()', 'Ref1 = g:FuncOneArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(number): number')
v9.CheckDefFailure(['var Ref1: func(bool)', 'Ref1 = g:FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(bool) but got func(bool, number)')
v9.CheckDefFailure(['var Ref1: func(?bool)', 'Ref1 = g:FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(?bool) but got func(bool, number)')
v9.CheckDefFailure(['var Ref1: func(...bool)', 'Ref1 = g:FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(...bool) but got func(bool, number)')
Expand Down Expand Up @@ -3355,7 +3355,7 @@ def Test_skip_cmds_with_silent()
enddef

def Test_opfunc()
nnoremap <F3> <cmd>set opfunc=Opfunc<cr>g@
nnoremap <F3> <cmd>set opfunc=g:Opfunc<cr>g@
def g:Opfunc(_: any): string
setline(1, 'ASDF')
return ''
Expand Down
2 changes: 1 addition & 1 deletion src/testdir/test_vim9_import.vim
Expand Up @@ -2018,7 +2018,7 @@ def Test_autoload_missing_function_name()
delete('Xdir', 'rf')
enddef

def Test_autoload_name_wring()
def Test_autoload_name_wrong()
var lines =<< trim END
vim9script
def Xscriptname#Func()
Expand Down

0 comments on commit 848fadd

Please sign in to comment.