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: body of broken function not cleared when using ":silent!" #8093

Closed
lacygoill opened this issue Apr 9, 2021 · 5 comments
Closed

Vim9: body of broken function not cleared when using ":silent!" #8093

lacygoill opened this issue Apr 9, 2021 · 5 comments

Comments

@lacygoill
Copy link

Describe the bug

In Vim9 script, :silent! might prevent Vim from clearing the body of a broken function.

To Reproduce

Run this shell command:

vim -Nu NONE -S <(cat <<'EOF'
    vim9script
    def Func()
        var x = 0 + {}
    enddef
    sil! Func()
    def Func
EOF
)

E1051 is raised:

E1051: Wrong argument type for +

This is expected.

The body of the function – as given by :def Func – remains the same:

   def <SNR>1_Func()
1          var x = 0 + {}
   enddef

This is not expected.

Expected behavior

The body of Func() is empty.

Environment

  • Vim version: 8.2 Included patches: 1-2741
  • OS: Ubuntu 16.04.7 LTS
  • Terminal: xterm(367)

Additional context

silent! doesn't prevent Vim from clearing the body of a broken function for other errors.

For example, if we try to re-declare a variable:

vim9script
def Func()
    var x = 0
    var x = 0
enddef
sil! Func()
def Func
function <SNR>1_Func()
endfunction

Or if we try to execute an invalid command:

vim9script
def Func()
    invalid
enddef
sil! Func()
def Func
function <SNR>1_Func()
endfunction

Or if we try to change the type of a variable:

vim9script
def Func()
    var x: number = 0
    x = ''
enddef
sil! Func()
def Func
function <SNR>1_Func()
endfunction

Notice that in all these snippets, Func() was invoked with silent! which correctly suppressed the error raised during the compilation. And notice that afterward, in all of them, the body of the function was empty.

If silent! does not prevent Vim from clearing the body of a broken function for these 3 errors, I would expect it does not prevent Vim from doing the same for the first one (E1051).


The fact that Vim clears the body of a function for which an error has been raised at compile time is neat. It's especially useful when the latter is invoked frequently; e.g. in an autocmd:

vim9script
def Func()
    invalid
enddef
Func()
au TextChangedI * Func()

This snippet raises E476 because of the initial Func() invocation on line 5:

E476: Invalid command: invalid

This is expected. But afterward, whenever a character is inserted, no error is raised. That's because Vim has cleared the body of the function after an error was raised during its compilation; which makes sense, if it can't be compiled, it will never work, and there's no reason to run anything; that would only bother the user whenever they try to insert a character.

This definition clearing should be done consistently and whenever possible. That's not the case when the error is E728:

vim9script
def Func()
    var x = 0 + {}
enddef
sil! Func()
au TextChangedI * Func()
feedkeys('ii')
E728: Using a Dictionary as a Number

Notice that this error is raised by the TextChangedI autocmd. And it will be repeated on every single keypress. This is useless. The function will never work; its definition should have been cleared during the compilation on its first invocation, regardless of whether silent! was used then.

@lacygoill
Copy link
Author

E1051 is raised:

E1051: Wrong argument type for +

This is expected.

Sorry, the error is not raised; it's suppressed by silent!. That doesn't change the rest of the report.

@lacygoill
Copy link
Author

Something else looks a bit weird.

When we ask for the definition of a broken :def function, Vim uses the keyword :function, not :def.

And when we invoke a broken function (because of E1051), which has not been cleared (because of :silent!), E728 is raised. Notice that E1051 is a new Vim9 error, while E728 is a "legacy" one (I mean it already existed before Vim9).

All of this suggests that a broken function is redefined as a legacy one. But that's not the case:

vim9script
def Func()
    echo (() => 123)()
    var x = 0 + {}
enddef
sil! Func()
au TextChangedI * Func()
feedkeys('ii')

This snippet correctly prints 123, which means that the new lambda syntax was correctly parsed, which would not be possible in a legacy function

@brammool
Copy link
Contributor

I actually think we should not delete the function body. This can be useful when the error message isn't clear and perhaps the script where it was defined is not easy to find. We then use a separate flag to specify that the function has an error and can't be executed.

This does mean that for an autocommand you get an error every time. That's not different from using a not compiled function though.

@lacygoill
Copy link
Author

The error message is different depending on whether the first invocation (when the function was compiled) was prefixed with silent! or not:

vim9script
def Func()
    var x = 0 + {}
enddef
Func()
au TextChangedI * Func()
feedkeys('ii')
Error detected while processing TextChangedI Autocommands for "*":
E1091: Function is not compiled: <SNR>1_Func
vim9script
def Func()
    var x = 0 + {}
enddef
sil! Func()
au TextChangedI * Func()
feedkeys('ii')
Error detected while processing TextChangedI Autocommands for "*"..function <SNR>1_Func:
line    1:
E728: Using a Dictionary as a Number

This seems inconsistent. I think the second message should tell us that Func() was not compiled, just like the first one.

@brammool
Copy link
Contributor

That was fixed with patch 8.2.2743

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