Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vim9: cannot read closure variable in debug mode #9951

Closed
lacygoill opened this issue Mar 14, 2022 · 4 comments
Closed

Vim9: cannot read closure variable in debug mode #9951

lacygoill opened this issue Mar 14, 2022 · 4 comments

Comments

@lacygoill
Copy link

Steps to reproduce

Run this shell command:

vim -Nu NONE -S <(tee <<'EOF'
    vim9script
    def Func()
        var s = 'rep'
        def Closure(): string
            return s
        enddef
        echo 'text'->substitute('.*', () => Closure(), '')
    enddef
    debug Func()
EOF
)

Execute >step to step into Func().
Execute >next to step over var s = 'rep'.
Execute >next to step over def Closure(): string.
Execute >step to step into the lambda () => Closure().
Execute >step to step into Closure().

Finally, execute >echo s; an error is given:

E121: Undefined variable: s

Expected behavior

No error is given because s is defined in the outer environment of Closure(), and the code works fine without :debug:

vim9script
def Func()
    var s = 'rep'
    def Closure(): string
        return s
    enddef
    echo 'text'->substitute('.*', () => Closure(), '')
enddef
Func()
rep

Version of Vim

8.2 Included patches: 1-4559

Environment

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

Additional context

At the script level, the exact same code does not give any error:

vim9script
var lines =<< trim END
    vim9script
    var s = 'rep'
    def Closure(): string
        return s
    enddef
    echo 'text'->substitute('.*', () => Closure(), '')
END
lines->writefile('/tmp/t.vim')
breakadd func Closure
source /tmp/t.vim
>echo s
rep

Although, in that case, we're no longer dealing with a closure...

@lacygoill
Copy link
Author

Unrelated, but why does adding a breakpoint on all lambda functions prevents Vim from finding a closure at compile time?

vim9script
def Func()
    var s = 'rep'
    def Closure(): string
        return s
    enddef
    echo 'text'->substitute('.*', () => Closure(), '')
enddef
breakadd func <lambda>*
Func()
E117: Unknown function: Closure

No such error if we add a breakpoint on all functions:

vim9script
def Func()
    var s = 'rep'
    def Closure(): string
        return s
    enddef
    echo 'text'->substitute('.*', () => Closure(), '')
enddef
breakadd func *
Func()

@brammool
Copy link
Contributor

For the first problem: The compiled function knows where to find the value of the variable. However, the debug "echo" command has no clue where to find it. This would be quite difficult to make work.

For the second problem: The closure is compiled without debugging when first encountering it. When it is later compiled for debugging the context is missing. I'll see if it can be compiled for debugging earlier.

@lacygoill
Copy link
Author

Now the help says this:

A closure must be compiled in the context that it is defined in, so that
variables in that context can be found.  This mostly happens correctly, except
when a function is marked for debugging with `breakadd` after it was compiled.
Make sure to define the breakpoint before compiling the outer function.

The last sentence seems to imply that there is a way to access variables from a closure in debug mode:

Make sure to define the breakpoint before compiling the outer function.

But it doesn't work. Test 1:

vim -Nu NONE -S <(tee <<'EOF'
    vim9script
    def Func()
        var s = 'rep'
        def Closure(): string
            return s
        enddef
        echo 'text'->substitute('.*', () => Closure(), '')
    enddef
    breakadd func Func
    Func()
EOF
)

>next
>next
>step
E1271: compiling closure without context: <lambda>1

Test 2:

vim -Nu NONE -S <(tee <<'EOF'
    vim9script
    def Func()
        var s = 'rep'
        def Closure(): string
            return s
        enddef
        echo 'text'->substitute('.*', () => Closure(), '')
    enddef
    breakadd func <lambda>*
    Func()
EOF
)

>step
>echo s
E121: Undefined variable: s

And yet, in both cases, the breakpoint is defined before calling or compiling any function.

@brammool
Copy link
Contributor

brammool commented Mar 19, 2022 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants