[vim/vim] Vim9: cannot use method call with imported and autoloaded function (Issue #9550)

9 views
Skip to first unread message

lacygoill

unread,
Jan 18, 2022, 5:50:08 AM1/18/22
to vim/vim, Subscribed

Steps to reproduce

Run this shell command:

vim -Nu NONE -S <(tee <<'EOF'
    vim9script
    var dir = '/tmp/.vim/autoload'
    dir->mkdir('p')
    var lines =<< trim END
        vim9script autoload
        export def Item(arg: string)
            echomsg arg
        enddef
    END
    lines->writefile(dir .. '/script.vim')
    set rtp^=/tmp/.vim
    import autoload 'script.vim'
    def Func()
        'base'->script.Item()
    enddef
    Func()
EOF
)

E121 is given:

E121: Undefined variable: g:script#Item

Expected behavior

No error is given. base is echo'ed.

Version of Vim

8.2 Included patches: 1-4128

Environment

Operating system: Ubuntu 20.04.3 LTS
Terminal: xterm
Value of $TERM: xterm-256color
Shell: zsh 5.8

Additional context

No issue if the method call is used at the script level:

vim9script
var dir = '/tmp/.vim/autoload'
dir->mkdir('p')
var lines =<< trim END
    vim9script autoload
    export def Item(arg: string)
        echomsg arg
    enddef
END
lines->writefile(dir .. '/script.vim')
set rtp^=/tmp/.vim
import autoload 'script.vim'
'base'->script.Item()
base

No issue when using a regular import/ script (i.e. not autoloaded):

vim9script
var dir = '/tmp/.vim/import'
dir->mkdir('p')
var lines =<< trim END
    vim9script
    export def Item(arg: string)
        echomsg arg
    enddef
END
lines->writefile(dir .. '/script.vim')
set rtp^=/tmp/.vim
import  'script.vim'
def Func()
    'base'->script.Item()
enddef
Func()
base


Reply to this email directly, view it on GitHub.
Triage notifications on the go with GitHub Mobile for iOS or Android.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/9550@github.com>

lacygoill

unread,
Jan 18, 2022, 5:50:57 AM1/18/22
to vim/vim, Subscribed

Also, if we try to import an autoloaded script, and Vim fails to find it, a confusing error is given:

vim9script
var dir = '/tmp/.vim/autoload'
dir->mkdir('p'
)
['vim9script autoload']->writefile(dir .. '/script.vim')
import autoload 'script.vim'
E1264: Autoload import cannot use absolute or relative path: script.vim

It's confusing because we can use a relative path:

vim9script
var dir = '/tmp/.vim/autoload'
dir->mkdir('p'
)
['vim9script autoload']->writefile(dir .. '/script.vim')
&runtimepath = '/tmp/.vim'
import autoload 'script.vim'
no error

There is an ambiguity: script.vim can be seen as a filename, or as a path relative to /tmp/.vim/autoload/.

Anyway, the issue is not that we have used a path (relative or absolute); the issue is simply that we haven't properly updated the runtimepath so that Vim can find the autoload directory containing the script.

A better error message would be:

E1234: cannot find autoload script "script.vim" in runtimepath


Reply to this email directly, view it on GitHub.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/9550/1015291883@github.com>

lacygoill

unread,
Jan 18, 2022, 5:53:43 AM1/18/22
to vim/vim, Subscribed

It's confusing because we can use a relative path:

Actually, what's really confusing is that Vim refers to script.vim as a path, while for the user it seems to be a simple file name.


Reply to this email directly, view it on GitHub.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/9550/1015294097@github.com>

lacygoill

unread,
Jan 18, 2022, 5:56:15 AM1/18/22
to vim/vim, Subscribed

Actually, what's really confusing is that Vim refers to script.vim as a path, while for the user it seems to be a simple file name.

I think the error message should be different depending on whether the argument passed to import autoload contains a path separator (slash on Unix-like systems, backslash on Windows?).


Reply to this email directly, view it on GitHub.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/9550/1015296050@github.com>

Bram Moolenaar

unread,
Jan 18, 2022, 7:46:39 AM1/18/22
to vim/vim, Subscribed


> **Steps to reproduce**

>
> Run this shell command:
>
> vim -Nu NONE -S <(tee <<'EOF'
> vim9script
> var dir = '/tmp/.vim/autoload'
> dir->mkdir('p')
> var lines =<< trim END
> vim9script autoload
> export def Item(arg: string)
> echomsg arg
> enddef
> END
> lines->writefile(dir .. '/script.vim')
> set rtp^=/tmp/.vim
> import autoload 'script.vim'
> def Func()
> 'base'->script.Item()
> enddef
> Func()
> EOF
> )
>
> `E121` is given:
>
> E121: Undefined variable: g:script#Item

Using disassemble we see that the instructions are trying to load
"script.Item" as a variable:


This happens because "script.Item" is compiled without knowing whether
it is a function reference or something else.

'base'->script.Item()
0 PUSHS "base"
1 LOADG g:script#Item
2 PCALL (argc 1)

Sourcing it again makes it work, because it uses PUSHFUNC:

'base'->script.Item()
0 PUSHS "base"
1 PUSHFUNC "script#Item"
2 PCALL (argc 1)

We'll have to deal with this at runtime.

--
Windows
M!uqoms

/// Bram Moolenaar -- ***@***.*** -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///


Reply to this email directly, view it on GitHub.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/9550/1015376603@github.com>

Bram Moolenaar

unread,
Jan 18, 2022, 7:59:27 AM1/18/22
to vim/vim, Subscribed

Closed #9550 via cbbc48f.


Reply to this email directly, view it on GitHub.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issue/9550/issue_event/5910353635@github.com>

lacygoill

unread,
Jan 18, 2022, 8:16:46 AM1/18/22
to vim/vim, Subscribed

This happens because "script.Item" is compiled without knowing whether
it is a function reference or something else.

I forgot: the issue only affected a method call:

# ERROR
'base'->script.Item()

# OK
script.Item('base')

I would have thought that if Vim was able to infer that script.Item was a function reference in the second case, it would come to the same conclusion in the first one.

We'll have to deal with this at runtime.

The error was already given at runtime. I hope it doesn't mean that we lose some type checking at compile time when we use a method call. Otherwise, I might be tempted to avoid methods when calling a function from an import autoload script.


Reply to this email directly, view it on GitHub.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/9550/1015402256@github.com>

Bram Moolenaar

unread,
Jan 18, 2022, 8:17:47 AM1/18/22
to vim/vim, Subscribed


> Also, if we try to import an autoloaded script, and Vim fails to find
> it, a confusing error is given:
> ```vim

> vim9script
> var dir = '/tmp/.vim/autoload'
> dir->mkdir('p')
> ['vim9script autoload']->writefile(dir .. '/script.vim')
> import autoload 'script.vim'
> ```
> E1264: Autoload import cannot use absolute or relative path: script.vim
>
> It's confusing because we *can* use a relative path:
> ```vim

> vim9script
> var dir = '/tmp/.vim/autoload'
> dir->mkdir('p')
> ['vim9script autoload']->writefile(dir .. '/script.vim')
> &runtimepath = '/tmp/.vim'
> import autoload 'script.vim'
> ```
> no error
>
> There is an ambiguity: `script.vim` can be seen as a filename, or as a path relative to `/tmp/.vim/autoload/`.

>
> Anyway, the issue is not that we have used a path (relative or absolute); the issue is simply that we haven't properly updated the runtimepath so that Vim can find the autoload directory containing the script.
>
> A better error message would be:
>
> E1234: cannot find autoload script "script.vim" in runtimepath

I'll fix that.

--
ARTHUR: Shut up! Will you shut up!
DENNIS: Ah, now we see the violence inherent in the system.
ARTHUR: Shut up!
DENNIS: Oh! Come and see the violence inherent in the system!
HELP! HELP! I'm being repressed!
The Quest for the Holy Grail (Monty Python)


/// Bram Moolenaar -- ***@***.*** -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///


Reply to this email directly, view it on GitHub.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/9550/1015403159@github.com>

Bram Moolenaar

unread,
Jan 18, 2022, 8:23:12 AM1/18/22
to vim...@googlegroups.com, lacygoill

> > This happens because "script.Item" is compiled without knowing whether
> > it is a function reference or something else.
>
> I forgot: the issue only affected a method call:
>
> # ERROR
> 'base'->script.Item()
>
> # OK
> script.Item('base')
>
> I would have thought that if Vim was able to infer that `script.Item`
> was a function reference in the second case, it would come to the same
> conclusion in the first one.

At the script level the autoload script needs to be loaded anyway, and
then we can figure out the type of "Item" before calling it.

> > We'll have to deal with this at runtime.
>
> The error was already given at runtime. I hope it doesn't mean that
> we lose some type checking at compile time when we use a method call.
> Otherwise, I might be tempted to avoid methods when calling a function
> from an import autoload script.

We do miss type checking at compile time, because the autoload script
has not been loaded. We can't load it without defeating the whole idea
of only loading it when used. Compiling a function does not always mean
it is used.

Perhaps we should make a difference between compiling a function because
'defcompile' is used and when we are actually going to call the
function? Still, compilation does not always mean we actually need to
load the autoload script:

import autoload "script.vim"
var someCondition = false
def MaybeCall()
if someCondition
script.Func()
endif
enddef
MaybeCall()

--
ARTHUR: Bloody peasant!
DENNIS: Oh, what a give away. Did you hear that, did you hear that, eh?
That's what I'm on about -- did you see him repressing me, you saw it
didn't you?
The Quest for the Holy Grail (Monty Python)

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
Reply all
Reply to author
Forward
0 new messages