function() get invalid funcref.

207 views
Skip to first unread message

mattn

unread,
Aug 7, 2014, 1:22:32 AM8/7/14
to vim...@googlegroups.com
Hi list.

----------------------------------------
let s:f = function('type')
let s:fref = function('s:f')
" => <SNR>1_f
echo call(s:fref, ['x'])
" => E117: Unknown function: <SNR>1_f
----------------------------------------

In this script, function('s:f') should be an error.

----------------------------------------
let s:fref = function('s:f')
----------------------------------------


diff -r 2a798dca16bf src/eval.c
--- a/src/eval.c Wed Aug 06 19:09:16 2014 +0200
+++ b/src/eval.c Thu Aug 07 14:01:26 2014 +0900
@@ -157,6 +157,7 @@
#define TFN_INT 1 /* internal function name OK */
#define TFN_QUIET 2 /* no error messages */
#define TFN_NO_AUTOLOAD 4 /* do not use script autoloading */
+#define TFN_NO_DEREF 8 /* do not deref function reference */

/* Values for get_lval() flags argument: */
#define GLV_QUIET TFN_QUIET /* no error messages */
@@ -22450,6 +22451,7 @@
* TFN_INT: internal function name OK
* TFN_QUIET: be quiet
* TFN_NO_AUTOLOAD: do not use script autoloading
+ * TFN_NO_DEREF: do not deref function reference
* Advances "pp" to just after the function name (if no error).
*/
static char_u *
@@ -22554,7 +22556,7 @@
if (name == lv.ll_exp_name)
name = NULL;
}
- else
+ else if (flags & TFN_NO_DEREF == 0)
{
len = (int)(end - *pp);
name = deref_func_name(*pp, &len, flags & TFN_NO_AUTOLOAD);
@@ -22786,8 +22788,8 @@
char_u *p;
int n = FALSE;

- p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET|TFN_NO_AUTOLOAD,
- NULL);
+ p = trans_function_name(&nm, FALSE,
+ TFN_INT|TFN_QUIET|TFN_NO_AUTOLOAD|TFN_NO_DEREF, NULL);
nm = skipwhite(nm);

/* Only accept "funcname", "funcname ", "funcname (..." and

Bram Moolenaar

unread,
Aug 7, 2014, 3:35:33 PM8/7/14
to mattn, vim...@googlegroups.com

Yasuhiro Matsumoto wrote:

> ----------------------------------------
> let s:f = function('type')
> let s:fref = function('s:f')
> " => <SNR>1_f
> echo call(s:fref, ['x'])
> " => E117: Unknown function: <SNR>1_f
> ----------------------------------------
>
> In this script, function('s:f') should be an error.
>
> ----------------------------------------
> let s:fref = function('s:f')
> ----------------------------------------

Thanks, I'll put it in the todo list.

--
A)bort, R)etry, P)lease don't bother me again

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///

Bram Moolenaar

unread,
Aug 17, 2014, 10:23:09 AM8/17/14
to mattn, vim...@googlegroups.com

Yasuhiro Matsumoto wrote:

> Hi list.
>
> ----------------------------------------
> let s:f = function('type')
> let s:fref = function('s:f')
> " => <SNR>1_f
> echo call(s:fref, ['x'])
> " => E117: Unknown function: <SNR>1_f
> ----------------------------------------
>
> In this script, function('s:f') should be an error.
>
> ----------------------------------------
> let s:fref = function('s:f')
> ----------------------------------------

After including this test_eval fails.

Since you have an example, can you turn that into a test?


--
hundred-and-one symptoms of being an internet addict:
32. You don't know what sex three of your closest friends are, because they
have neutral nicknames and you never bothered to ask.
normal GA<CR><Esc>

Bram Moolenaar

unread,
Aug 17, 2014, 10:26:00 AM8/17/14
to mattn, vim...@googlegroups.com

I wrote:

> Yasuhiro Matsumoto wrote:
>
> > Hi list.
> >
> > ----------------------------------------
> > let s:f = function('type')
> > let s:fref = function('s:f')
> > " => <SNR>1_f
> > echo call(s:fref, ['x'])
> > " => E117: Unknown function: <SNR>1_f
> > ----------------------------------------
> >
> > In this script, function('s:f') should be an error.
> >
> > ----------------------------------------
> > let s:fref = function('s:f')
> > ----------------------------------------
>
> After including this test_eval fails.
>
> Since you have an example, can you turn that into a test?

Oh, I did change one line:

+ else if (flags & TFN_NO_DEREF == 0)

That should be:

else if ((flags & TFN_NO_DEREF) == 0)


--
hundred-and-one symptoms of being an internet addict:
32. You don't know what sex three of your closest friends are, because they
have neutral nicknames and you never bothered to ask.

mattn

unread,
Aug 18, 2014, 3:04:46 AM8/18/14
to vim...@googlegroups.com, matt...@gmail.com
Oops, sorry.

Bram Moolenaar

unread,
Sep 9, 2014, 7:39:12 AM9/9/14
to mattn, vim...@googlegroups.com

Yasuhiro Matsumoto wrote:

> ----------------------------------------
> let s:f = function('type')
> let s:fref = function('s:f')
> " => <SNR>1_f
> echo call(s:fref, ['x'])
> " => E117: Unknown function: <SNR>1_f
> ----------------------------------------
>
> In this script, function('s:f') should be an error.
>
> ----------------------------------------
> let s:fref = function('s:f')
> ----------------------------------------
>
>
> diff -r 2a798dca16bf src/eval.c
> --- a/src/eval.c Wed Aug 06 19:09:16 2014 +0200
> +++ b/src/eval.c Thu Aug 07 14:01:26 2014 +0900

[...]

This patch breaks a test. I had postponed including it for that reason.
Also, since you can reproduce the problem, we should add a test for
that.


--
Laughing helps. It's like jogging on the inside.

mattn

unread,
Nov 1, 2014, 9:49:13 AM11/1/14
to vim...@googlegroups.com, matt...@gmail.com
Updated patch.

In testdir/test_eval_func.vim
-------------
func! s:Testje()
return "foo"
endfunc
let Bar = function('s:Testje')
$put ='func Bar exists: ' . exists('*Bar')
-------------

This should be: "func Bar exists: 0"

https://gist.github.com/mattn/6e69a3a76fb14a6a286b

Bram Moolenaar

unread,
Nov 2, 2014, 8:09:18 AM11/2/14
to mattn, vim...@googlegroups.com
Does this actually have to change? If I execute those lines (using a
script file) and then do:

:echo Bar()

It works. I think if a script intentionally exports a script-local
function, it's fine that it works.

--
[clop clop]
ARTHUR: Old woman!
DENNIS: Man!
ARTHUR: Man, sorry. What knight lives in that castle over there?
DENNIS: I'm thirty seven.
ARTHUR: What?
DENNIS: I'm thirty seven -- I'm not old!
The Quest for the Holy Grail (Monty Python)

LCD 47

unread,
Nov 3, 2014, 3:47:00 AM11/3/14
to vim...@googlegroups.com
On 2 November 2014, Bram Moolenaar <Br...@moolenaar.net> wrote:
>
> Yasuhiro Matsumoto wrote:
>
> > Updated patch.
> >
> > In testdir/test_eval_func.vim
> > -------------
> > func! s:Testje()
> > return "foo"
> > endfunc
> > let Bar = function('s:Testje')
> > $put ='func Bar exists: ' . exists('*Bar')
> > -------------
> >
> > This should be: "func Bar exists: 0"
> >
> > https://gist.github.com/mattn/6e69a3a76fb14a6a286b
>
> Does this actually have to change? If I execute those lines (using a
> script file) and then do:
>
> :echo Bar()
>
> It works. I think if a script intentionally exports a script-local
> function, it's fine that it works.

Yes, and there are plugins relying on the current behaviour.

/lcd

mattn

unread,
Nov 3, 2014, 11:44:00 AM11/3/14
to vim...@googlegroups.com, matt...@gmail.com
Can you explain this behavior in docs for users?

-------------------------
function! s:type(x)
return a:x
endfunction

let s:type = function('type')
" => E705
-------------------------

function! Type(x)
return a:x
endfunction

let Type = function('type')
" => E705
-------------------------

function! s:type(x)
return a:x
endfunction

let s:type = 0

echo s:type('x')
" => 'x'
-------------------------

let s:type = function('type')

function! s:type(x)
return a:x
endfunction

echo s:type('x')
" => 1
-------------------------

let s:type = function('type')

function! s:type(x)
return a:x
endfunction

let s:type = function('type')

echo s:type('x')
" => 1

Bram Moolenaar

unread,
Nov 3, 2014, 3:25:20 PM11/3/14
to mattn, vim...@googlegroups.com

Yasuhiro Matsumoto wrote:

> Can you explain this behavior in docs for users?

Yes.

> -------------------------
> function! s:type(x)
> return a:x
> endfunction
>
> let s:type = function('type')
> " => E705
> -------------------------

I do not get this error.

> function! Type(x)
> return a:x
> endfunction
>
> let Type = function('type')
> " => E705
> -------------------------

Correct, Type was already defined, you can't define a variable with the
same name.

>
> function! s:type(x)
> return a:x
> endfunction
>
> let s:type = 0
>
> echo s:type('x')
> " => 'x'
> -------------------------

That looks like a bug, should not allow assignment to s:type.

> let s:type = function('type')
>
> function! s:type(x)
> return a:x
> endfunction
>
> echo s:type('x')
> " => 1
> -------------------------

Same bug the other way around.

> let s:type = function('type')
>
> function! s:type(x)
> return a:x
> endfunction
>
> let s:type = function('type')
>
> echo s:type('x')
> " => 1

Looks like the same thing.

So the bug appears to be that it's possible to have a variable and a
function with the same name when they are script-local.

--
WOMAN: I didn't know we had a king. I thought we were an autonomous
collective.
DENNIS: You're fooling yourself. We're living in a dictatorship. A
self-perpetuating autocracy in which the working classes--
WOMAN: Oh there you go, bringing class into it again.
DENNIS: That's what it's all about if only people would--

LCD 47

unread,
Nov 4, 2014, 2:21:45 AM11/4/14
to vim...@googlegroups.com
I can: "Trying to overload internal Vim functions with script-local
functions with the same name is a really bad idea. It probably won't do
what you expect." :)

/lcd

LCD 47

unread,
Nov 4, 2014, 2:25:58 AM11/4/14
to vim...@googlegroups.com
On 3 November 2014, Bram Moolenaar <Br...@moolenaar.net> wrote:
>
> Yasuhiro Matsumoto wrote:
>
> > Can you explain this behavior in docs for users?
>
> Yes.
>
> > -------------------------
> > function! s:type(x)
> > return a:x
> > endfunction
> >
> > let s:type = function('type')
> > " => E705
> > -------------------------
>
> I do not get this error.
[...]

Hmm, I do get E705 here, with Vim 7.4.493.

/lcd

Ken Takata

unread,
Jul 22, 2016, 11:15:53 PM7/22/16
to vim_dev
Hi mattn,

2014/8/7 Thu 14:22:32 UTC+9 mattn wrote:
> Hi list.
>
> ----------------------------------------
> let s:f = function('type')
> let s:fref = function('s:f')
> " => <SNR>1_f
> echo call(s:fref, ['x'])
> " => E117: Unknown function: <SNR>1_f
> ----------------------------------------
>
> In this script, function('s:f') should be an error.
>
> ----------------------------------------
> let s:fref = function('s:f')
> ----------------------------------------

How about this patch?
https://bitbucket.org/k_takata/vim-ktakata-mq/src/535170f9175dbfd922535d585a4b63736329b209/function-noderef.patch?at=default

This doesn't break existing tests.
I'm not sure which file should I add new tests for this to.

Regards,
Ken Takata

Bram Moolenaar

unread,
Jul 23, 2016, 8:01:44 AM7/23/16
to Ken Takata, vim_dev
I think test_expr.vim is a good place. But perhaps this test also needs
to include another script to check passing a script-local function in a
funcref to another script?

--
There are three kinds of people: Those who can count & those who can't.

Ken Takata

unread,
Jul 31, 2016, 3:16:33 AM7/31/16
to vim_dev, ktakat...@gmail.com
Hi,

2016/7/23 Sat 21:01:44 UTC+9 Bram Moolenaar wrote:
> Ken Takata wrote:
>
> > 2014/8/7 Thu 14:22:32 UTC+9 mattn wrote:
> > > Hi list.
> > >
> > > ----------------------------------------
> > > let s:f = function('type')
> > > let s:fref = function('s:f')
> > > " => <SNR>1_f
> > > echo call(s:fref, ['x'])
> > > " => E117: Unknown function: <SNR>1_f
> > > ----------------------------------------
> > >
> > > In this script, function('s:f') should be an error.
> > >
> > > ----------------------------------------
> > > let s:fref = function('s:f')
> > > ----------------------------------------
> >
> > How about this patch?
> > https://bitbucket.org/k_takata/vim-ktakata-mq/src/535170f9175dbfd922535d585a4b63736329b209/function-noderef.patch?at=default
> >
> > This doesn't break existing tests.
> > I'm not sure which file should I add new tests for this to.
>
> I think test_expr.vim is a good place. But perhaps this test also needs
> to include another script to check passing a script-local function in a
> funcref to another script?

I added very simple test.

* function(s:f) works, but
* function('s:f') causes an error.

Please check the following patch:
https://bitbucket.org/k_takata/vim-ktakata-mq/src/95e9a10fea18993f6dcc710364c2908acb1e2caa/function-noderef.patch?at=default

Regards,
Ken Takata

Bram Moolenaar

unread,
Jul 31, 2016, 8:12:23 AM7/31/16
to Ken Takata, vim_dev
Thanks. Do we need to mention this in the help somewhere?

--
LETTERS TO THE EDITOR (The Times of London)

Dear Sir,

I am firmly opposed to the spread of microchips either to the home or
to the office.  We have more than enough of them foisted upon us in
public places.  They are a disgusting Americanism, and can only result
in the farmers being forced to grow smaller potatoes, which in turn
will cause massive unemployment in the already severely depressed
agricultural industry.

Yours faithfully,
        Capt. Quinton D'Arcy, J. P.
        Sevenoaks
Reply all
Reply to author
Forward
0 new messages