Fix: #16379
https://github.com/vim/vim/pull/16440
(5 files)
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
thanks. Does it make sense to (re-)use 'maxfuncdept' for that?
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Does this mean that I should check the value of 'maxfuncdepth' (p_mfd) instead of "MAX_IMPORT_NESTING"?
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
yes
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
@h-east pushed 1 commit.
—
View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Done.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
With this patch, vim -u NONE works fine, but when I use my vimrc with a few plugins (lsp, vimcomplete, vimsuggest, vim-tene), it spams the whole terminal with E1045.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
can you please reproduce with a minimal vimrc?
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
With only the runtime path to my plugins folder and VimComplete (https://github.com/girishji/vimcomplete) installed, Vim "opens" but it seizes immediately and hitting enter just repeats the error.
Error detected while processing VimEnter Autocommands for "*"..function <SNR>53_VimCompEnable[11]..vimcomplete#completor#Enable[40]..script
/nix/store/5y1nk7df36wmfxj18ny5qhg8qspcp4jq-vimplugin-vimcomplete/autoload/vimcomplete/util.vim:
line 218:
E1045: Import nesting too deep
vim9script
set nocompatible
set packpath^=/nix/store/...-vim-pack-dir
set runtimepath^=/nix/store/...-vim-pack-dir
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
There is a circular reference between util.vim and completor.vim in autoload/vimcomplete/.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Perhaps Vim should handle the issue more gracefully; the current error handling is rather haphazard (the terminal becomes unresponsive).
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
@h-east Are you going to fix this to allow circular imports? If circular imports are going to be disallowed, then doc needs to change. It may break other plugins also.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
@girishji No, I do not intend to allow circular references. The reason is that multi-level references cannot be realized. I am considering improving the documentation.
(The final decision will be made by @chrisbra )
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
@chrisbra
I'll add a following error code to include a mechanism to detect circular references?
EXTERN char e_circular_reference_occurs_in_import_str[] INIT(= N_("E1046: A circular reference occurs in import: %s"));
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
my plugin https://github.com/habamax/vim-dir is broken now
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
No, I do not intend to allow circular references. The reason is that multi-level references cannot be realized. I am considering improving the documentation.
This is quite unexpected considering all messages about backward compatibility.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Yeah, that is an unpleasant surprise that this causes issues with so many plugins. I think detecting circular dependencies and warning about it is actually a good thing to do. But since this causes so much pain, let's just put that behind a verbose option value, so that it normally does not warn.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
I fixed 2 of my plugins to remove circular references. I am ok with removing support for circular imports. Generally it is discouraged or not allowed in other languages. In vim9script, it was giving an impression that circular imports are somehow OK (when it wasn't). I am in favor of updating the document to suggest ways to mitigate the use of circular imports (ex. use :h User, or refactor, etc.). I understand that plugin authors may have to fix their plugins.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
I have fixed my plugin as well, nevertheless, it might break many other plugins.
Am I correct assuming that this fix will make vim9script less capable than legacy vimscript for autoloaded modules? I would be able to have "circular references" in legacy but not in vim9script?
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
legacy vimscript should not be affected by this, because we don't have import mechanism and you as an author are responsible for managing your dependencies manually (by making sure required files are available and sourcing them manually). So no, I don't think this makes Vim9script less capable.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
legacy vimscript should not be affected by this, because we don't have import mechanism and you as an author are responsible for managing your dependencies manually (by making sure required files are available and sourcing them manually). So no, I don't think this makes Vim9script less capable.
Here is legacy vs vim9script:
autoload/module1.vim
func module1#hello()
echom "hello"
endfunc
func module1#run()
call module1#hello()
call module2#world()
endfunc
autoload/module2.vim
func module2#world()
echom "world"
endfunc
func module2#run()
call module1#hello()
call module2#world()
endfunc
When I run :call module1#run() or :call module2#run() -- it works without errors.
"Same" thing with vim9script goes with errors:
autoload/module19.vim
vim9script
import autoload "module29.vim"
export def Hello()
echom "hello"
enddef
export def Run()
Hello()
module29.World()
enddef
autoload/module29.vim
vim9script
import autoload "module19.vim"
export def World()
echom "world"
enddef
export def Run()
module19.Hello()
World()
enddef
Running :echo module29#Run()
image.png (view on web)
Restart vim and run :echo module19#Run()
image.png (view on web)
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
In legacy vimscript I can call autoloaded functions the way I can't now in vim9script.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
by making sure required files are available and sourcing them manually
I believe autoloaded scripts didn't mean to be sourced manually in legacy vimscript. And I was under impression that import autoload is about making exported names available to call without loading the actual file which should happen on the function call.
Also, original problem as far as I can see was about import not import autoload so the change is quite significant.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
I wonder if this was just an implementation bug/error, cause updated help topic states This does not apply to autoload imports?
*:import-cycle* *E1045*
The `import` commands are executed when encountered. It can be nested up to
'maxfuncdepth' levels deep. If script A imports script B, and B (directly or
indirectly) imports A, this will be skipped over. At this point items in A
after "import B" will not have been processed and defined yet. Therefore
cyclic imports can exist and not result in an error directly, but may result
in an error for items in A after "import B" not being defined. This does not
apply to autoload imports, see the next section.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
I was not aware of how legacy script worked. I still see a fundamental difference b/w the two scripts. It appears, legacy script is capable of executing selected functions from other script without bothering with other contents of the script. This appears intuitive since there is no compiling, unlike vim9script. This means there will be no circular dependencies in some situations in legacy script (like the above example). The same example in vim9script will cause circular reference since the whole script gets compiled when imported. autoload merely delays the compilation. To make vim9script work on par with legacy script, it should be capable of compiling and executing specific functions on-demand, and not compile the whole script (and deal with circular references). This is in reference to import autoload.
(Aside: This means, there is no need for import autoload xxx.vim for scripts in autoload/. Other scripts should be able to call functions like xxx.foo() without having to import (like legacy script)).
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
To bring vim9script on par with legacy scripts, it would need to support on-demand compilation and execution of specific functions (during
import autoload), rather than compiling the entire script upfront and dealing with circular references.
Funny thing here is that you can have this in vim9script using legacy autoload calls:
autoload/module19.vim:
vim9script
export def Hello()
echom "hello"
enddef
export def Run()
Hello()
module29#World()
enddef
autoload/module29.vim:
vim9script
export def World()
echom "world"
enddef
export def Run()
module19#Hello()
World()
enddef
Then :call module19#Run() or :call module29#Run() works just fine.
Which makes current implementation of import autoload a bit less appealing to use.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Here is my suggestion (solution):
import x.vim: This compiles and executes the x.vim file immediately. Compilation refers only to functions. Circular imports are not allowed.
import autoload x.vim: Similar to the above, except the processing is deferred until one of its functions is invoked. Circular imports are also not allowed.
Calling x#foo() from y.vim without import: In this case, only the foo() function is compiled and executed. This works like a "forward reference." This allows us to support circular references. This is not documented currently. I hope we can do a#b#c#foo() for foo() inautoload/a/b/c.vim. I can see this being less efficient than import autoload. I also hope bytecode from complied foo() gets cached.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Well, there is this issue #16379 which this patch resolves, which we (hopefully) all agree on that need to be fixed. Personally I believe circular dependencies should not be allowed and need to be fixed in the plugin instead. That the same is possible using legacy vimscript using autoload mechanism doesn't mean we should allow it for Vim9 script, and you can still use this, if you really need to (which you just found out). But this really looks like a hack.
If this really causes too much trouble, we can roll back this patch, but I am not yet convinced.
And I'd like to hear from others @dkearns @yegappan @zeertzjq @h-east for input.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
I think that not treating circular references as errors is a disadvantage, not an advantage. A circular reference state indicates that the design of module separation is insufficient, and continuing to write code in that state promotes spaghetti code.
However, if many existing plugins result in errors, We think it is necessary to consider some countermeasures.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
CharGPT's response:
Languages that allow circular references include Python, JavaScript, and Ruby, but it is recommended to avoid them at the design stage as they can cause instability in operation and complicate design. On the other hand, Rust and Go prohibit circular references and require clarification of dependencies.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Circular dependencies are never needed. It's a useless, logically flawed, complication.
Where in the documentation did you get the idea that cyclic imports are supported? At least in Vim 9.1.727 (the version I'm using now), :help :import-cycle is pretty clear:
if script A imports B, and B (directly on indirectly) imports A [...this] may result in an error for items in A after "import B" not being defined.
That is: “beware that Vim doesn't have code to detect cycles (yet), but since they have bad effects you should be careful not to create them.”
The following sentence says:
this does not apply to autoload imports
and it's admittedly misleading, because it refers only to the fact that if script A autoload-imports B which imports A, you won't get an error at the time import autoload is executed (and possibly not even some time after that) because nothing is imported right away. But :help vim9-autoload explains that, if in the middle of script A there's a reference to an item in B then that triggers the import of B. If B references an item in A that has not been compiled yet, you'll still get an error. Example:
autoload/module19.vim
vim9script import autoload "module29.vim" # module29 is NOT imported here # But the following causes module29 to be imported. At this point, Hello() is not defined. module29.World()
export def Hello() echom "hello" enddef
autoload/module29.vim
vim9script import autoload "module19.vim"
export def World() echom "world" enddef export def Run
()
module19.Hello() # This triggers an error when Run() is called
World()
enddef
Run()Cyclic autoload imports might in some cases work as you'd expect (but also normal imports, for that matter), but they are very fragile. It's a good thing that Vim now is stricter about that.
I agree that the documentation can be improved.
@habamax As I hope to have clarified above, this is not to be considered a breakage of backward compatibility because it was never a feature.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@habamax As I hope to have clarified above, this is not to be considered a breakage of backward compatibility because it was never a feature.
I would argue about breakage but nevertheless this is not something I would fight for, so let's keep going.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
I think that disallowing this would be most in keeping with the general design of Vim9.
And I don't think I've ever seen @lifepillar argue so stridently for something before. :)
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Apologies if my tone sounded overbearing. Just to be clear, my question was not rhetorical. And yes, maybe I accidentally leaked that I'm not a huge fan of circularity :-)
disallowing this would be most in keeping with the general design of Vim9.
I agree. The first commit by Bram adding the import-cycle section reads as follows:
The `import` commands are executed when encountered. If that script (directly
or indirectly) imports the current script, then items defined after the
`import` won't be processed yet. Therefore cyclic imports can exist, but may
result in undefined items.
I don't think he ever wanted to allow that as a feature. My guess is that on implementing import he considered it sufficient to warn about circularity issues rather than coding a check for that—at least on the first iterations of the import feature.
With respect to backward compatibility: this issue was probably one of few open loops left (pun intended), but we have to consider that for a complex feature such as a full programming language missteps or second thoughts do happen (changing this to var at some point in class instance variables pops to my mind).
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
I believe that it's a widely shared opinion that backward compatibility should remain a staple of Vim's goals.
This particular issue is a story in its own right, I would say, because imo the documentation did not do a good enough job to keep users away from using a “feature” that was not supposed to be used.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
There is another pain point with this patch.
Consider a type hierarchy:
a.vim:
vim9script export interface A endinterface export const TEXT: string = 'a'
b.vim:
vim9script import './a.vim' as acme export class B implements acme.A endclass const a: string = acme.TEXT
where a.vim and b.vim come from a third-party library we
have no control over.
Suppose we want to use this library as follows:
test.vim:
vim9script import './b.vim' import './a.vim' class C extends b.B endclass export const acme: string = repeat(a.TEXT, 4)
and... we have to rename acme on account of its clashing
with :import-as from b.vim.
Should :import-as names leak into other scripts and be
treated as API artifacts? How can we protect our own API
artifacts from clashing with future library versions that
may introduce for their own needs the same :import-as
names? Must library authors refrain from using :import-as
in their libraries?
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
That seems a regression: before this patch, acme in b.vim was script-local—which should be the correct behavior.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@chrisbra and All,
I'm investigating and I realize the solution in this PR is a bad one.
Probably there will be more problems.
First of all, could you please revert 9.1.1014?
I haven't written a nice patch yet. Sorry. Please give me a more time.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
sure
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()