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

Initial implementation of nimsuggest v3 #19826

Merged
merged 7 commits into from
Jun 13, 2022

Conversation

yyoncho
Copy link
Contributor

@yyoncho yyoncho commented May 24, 2022

Rework nimsuggest to use caching to make usage of ide commands more efficient.
Previously, all commands no matter what the state of the process is were causing
clean build. In the context of Language Server Protocol(LSP) and lsp clients
this was causing perf issues and overall instability. Overall, the goal of v3 is
to fit to LSP Server needs

  • added two new commands:

    • recompile to do clean compilation
    • changed which can be used by the IDEs to notify that a particular file has been changed.
      The later can be utilized when using LSP file watches.
    • globalSymbols - searching global references
  • added segfaults dependency to allow fallback to clean build when incremental
    fails. I wish the error to be propagated to the client so we can work on fixing
    the incremental build failures (typically hitting pointer)

  • more efficient rebuild flow. ATM incremental rebuild is triggered when the
    command needs that(i. e. it is global) while the commands that work on the
    current source rebuild only it

Things missing in this PR:

  • Documentation
  • Extensive unit testing.

Although functional I still see this more as a POC that this approach can work.

Next steps:

  • Implement sug request.
  • Rework/extend the protocol to allow better client/server communication.
    Ideally we will need push events, diagnostics should be restructured to allow
    per file notifications, etc.
  • implement v3 test suite.
  • better logging

suggestResult(graph.config, sug)
of ideGlobalSymbols:
var counter = 0
let reg = re(string(file))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a need for this to be a regex? Can't it be done with contains (in) or something similar?

Copy link

@ghost ghost May 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code below seems to do find(cstring(sym.name.s), reg, 0, sym.name.s.len) , you can instead just use https://nim-lang.org/docs/strutils.html#find%2Cstring%2Cstring%2CNatural%2Cint to get the position of the first match

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is my personal preference. It will be pretty much up to us to decide whether to run with regex or with startsWith or with in. If we talk about other language servers some of them are using glob, and some of them use startsWith.

Copy link

@ghost ghost May 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yyoncho the problem is that it affects more than just personal preference - Nim's re library depends on PCRE, so if you make nimsuggest depend on re, users will have to make sure they have pcre installed. In a simple case like this I really think you should just use strutils.find.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yyoncho the problem is that it affects more than just personal preference

Of course - I am just saying why I picked this implementation. Using find should be good enough for the initial implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Yardanico changed to contains. I was wondering whether to downcase before matching but I guess it might lead to too many matches.

@yyoncho
Copy link
Contributor Author

yyoncho commented Jun 4, 2022

Friendly ping.

import strformat
import tables
import std/sha1
import segfaults
Copy link
Member

@Araq Araq Jun 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is import segfaults required? Remove this, don't continue after segfaults, fix segfaults properly as they arise.

Copy link
Contributor Author

@yyoncho yyoncho Jun 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea here is to catch segfaults as part of incremental recompilation and then do a clean compilation. In some of the future commits I will change to code to send the notification to the client about that failure to make sure that these crashes are not lost and after that properly fixed. Note that in any other case the uncaught exception will trigger that same behavior - the application will exit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To elaborate a bit more - I am trying to make nimsuggest more crash resilient to eliminate the need for having an external process wrapper(i. e. nimlangserver).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am also planning to replace quit calls in the compiler with throw exception (in case nimsuggest) to make crashes less likely. Please share your thoughts.

Copy link
Member

@Araq Araq Jun 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compiler keeps a tremendous amount of state around. This is pretty bad already and not easily fixed. If you continue after a bug the state becomes "corrupt", not necessarily in the sense that it causes a crash. A crash can easily be detected by nimlangserver or the like and the service can be restarted. If you instead make crashes disappear and at the same time nimsuggest produces wrong output, missing output etc then it becomes less trustworthy. It's not a good idea, Erlang's "let it crash" philosophy is the right idea and it relies on process isolation.

Process isolation is crucial for reliability. What we can do is to make nimsuggest a supervisor process like nimlangserver so that editor support does not have to reimplement the supervisor logic. Nimsuggest would then call something like a nimsuggest_worker process.

Copy link
Contributor Author

@yyoncho yyoncho Jun 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A crash can easily be detected by nimlangserver or the like and the service can be restarted.

I had that same conversation with @zah - the problem here is that there is no easy way to detect where the crash comes from - if the crash comes from something else and nimlangserver restarts nimsuggest then the result might be a loop.

The process isolation is crucial for reliability. What we can do is to make nimsuggest a supervisor process like nimlangserver so that editor support does not have to reimplement the supervisor logic. Nimsuggest would then call something like a nimsuggest_worker process.

Isn't throwing away ModuleGraph equivalent to starting a clean process? My understanding is that there is no state outside of ModuleGraph. Or you have other concerns? FWIW I have tried to emulate creating "fresh" module graph in initModuleGraphFields which will be called after recompile crashes. If we remove segfaults then we should remove the catch block here: https://github.com/yyoncho/Nim/blob/nimsuggest-version-3/nimsuggest/nimsuggest.nim#L707 because it no longer makes sense if the strategy is let it crash. The java language server has a similar strategy in a slightly different context - it performs incremental builds as you type but in addition it has a command Clean build which is for the cases when the server context breaks up.

If you don't buy these arguments what do you think about having this behavior behind a build flag?

PS: I see this code evolving and this "patch" is something that will go away once we address more and more recompilaton-related bugs. I have identified a few but I wanted to come up with something as usable as possible and then focus on fixing them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

throw exception

generally, in a compiler api built for tooling, exceptions are not the way to go in many / most cases - instead you want to collect errors along the way without aborting the process, meaning that you pass in some collector - if we're removing quit and the like, this is likely a better way to go

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arnetheduck afaics that is what is happening in practice, it is just that when the collected error kind is in fatalMsgs it quits (https://github.com/yyoncho/Nim/blob/nimsuggest-version-3/compiler/lineinfos.nim#L214 ). So it is either throw an exception or let it continue. I guess for nimsuggest both should be good enough as long as it does not crash the process.

@Araq
Copy link
Member

Araq commented Jun 8, 2022

Apart from the import segfaults it's fine.

@yyoncho
Copy link
Contributor Author

yyoncho commented Jun 13, 2022

So I removed the import segfaults line to unblock the PR. I guess we can sort out that later.

Rework `nimsuggest` to use caching to make usage of ide commands more efficient.
Previously, all commands no matter what the state of the process is were causing
clean build. In the context of Language Server Protocol(LSP) and lsp clients
this was causing perf issues and overall instability. Overall, the goal of v3 is
to fit to LSP Server needs

- added two new commands:
  - `recompile` to do clean compilation
  - `changed` which can be used by the IDEs to notify that a particular file has been changed.
The later can be utilized when using LSP file watches.
  - `globalSymbols` - searching global references

- added `segfaults` dependency to allow fallback to clean build when incremental
fails. I wish the error to be propagated to the client so we can work on fixing
the incremental build failures (typically hitting pointer)

- more efficient rebuild flow. ATM incremental rebuild is triggered when the
command needs that(i. e. it is global) while the commands that work on the
current source rebuild only it

Things missing in this PR:

- Documentation
- Extensive unit testing.

Although functional I still see this more as a POC that this approach can work.

Next steps:
- Implement `sug` request.
- Rework/extend the protocol to allow better client/server communication.
Ideally we will need push events, diagnostics should be restructored to allow
per file notifications, etc.
- implement v3 test suite.
- better logging
@Araq Araq added the merge_when_passes_CI mergeable once green label Jun 13, 2022
@Araq Araq merged commit b412260 into nim-lang:devel Jun 13, 2022
yyoncho added a commit to yyoncho/Nim that referenced this pull request Jun 13, 2022
* Initial implementation of nimsuggest v3

Rework `nimsuggest` to use caching to make usage of ide commands more efficient.
Previously, all commands no matter what the state of the process is were causing
clean build. In the context of Language Server Protocol(LSP) and lsp clients
this was causing perf issues and overall instability. Overall, the goal of v3 is
to fit to LSP Server needs

- added two new commands:
  - `recompile` to do clean compilation
  - `changed` which can be used by the IDEs to notify that a particular file has been changed.
The later can be utilized when using LSP file watches.
  - `globalSymbols` - searching global references

- added `segfaults` dependency to allow fallback to clean build when incremental
fails. I wish the error to be propagated to the client so we can work on fixing
the incremental build failures (typically hitting pointer)

- more efficient rebuild flow. ATM incremental rebuild is triggered when the
command needs that(i. e. it is global) while the commands that work on the
current source rebuild only it

Things missing in this PR:

- Documentation
- Extensive unit testing.

Although functional I still see this more as a POC that this approach can work.

Next steps:
- Implement `sug` request.
- Rework/extend the protocol to allow better client/server communication.
Ideally we will need push events, diagnostics should be restructored to allow
per file notifications, etc.
- implement v3 test suite.
- better logging

* Add tests for v3 and implement ideSug

* Remove typeInstCache/procInstCache cleanup

* Add ideChkFile command

* Avoid contains call when adding symbol info

* Remove log

* Remove segfaults
Araq pushed a commit that referenced this pull request Jun 19, 2022
* Initial implementation of nimsuggest v3 (#19826)

* Initial implementation of nimsuggest v3

Rework `nimsuggest` to use caching to make usage of ide commands more efficient.
Previously, all commands no matter what the state of the process is were causing
clean build. In the context of Language Server Protocol(LSP) and lsp clients
this was causing perf issues and overall instability. Overall, the goal of v3 is
to fit to LSP Server needs

- added two new commands:
  - `recompile` to do clean compilation
  - `changed` which can be used by the IDEs to notify that a particular file has been changed.
The later can be utilized when using LSP file watches.
  - `globalSymbols` - searching global references

- added `segfaults` dependency to allow fallback to clean build when incremental
fails. I wish the error to be propagated to the client so we can work on fixing
the incremental build failures (typically hitting pointer)

- more efficient rebuild flow. ATM incremental rebuild is triggered when the
command needs that(i. e. it is global) while the commands that work on the
current source rebuild only it

Things missing in this PR:

- Documentation
- Extensive unit testing.

Although functional I still see this more as a POC that this approach can work.

Next steps:
- Implement `sug` request.
- Rework/extend the protocol to allow better client/server communication.
Ideally we will need push events, diagnostics should be restructored to allow
per file notifications, etc.
- implement v3 test suite.
- better logging

* Add tests for v3 and implement ideSug

* Remove typeInstCache/procInstCache cleanup

* Add ideChkFile command

* Avoid contains call when adding symbol info

* Remove log

* Remove segfaults

* Fixed bad cherry-pick resolve

* modulegraphs.dependsOn does not work on transitive modules

- make sure transitive deps are marked as dirty
EmilIvanichkovv pushed a commit to metacraft-labs/nim that referenced this pull request Aug 19, 2022
…im-lang#19892)

* Initial implementation of nimsuggest v3 (nim-lang#19826)

* Initial implementation of nimsuggest v3

Rework `nimsuggest` to use caching to make usage of ide commands more efficient.
Previously, all commands no matter what the state of the process is were causing
clean build. In the context of Language Server Protocol(LSP) and lsp clients
this was causing perf issues and overall instability. Overall, the goal of v3 is
to fit to LSP Server needs

- added two new commands:
  - `recompile` to do clean compilation
  - `changed` which can be used by the IDEs to notify that a particular file has been changed.
The later can be utilized when using LSP file watches.
  - `globalSymbols` - searching global references

- added `segfaults` dependency to allow fallback to clean build when incremental
fails. I wish the error to be propagated to the client so we can work on fixing
the incremental build failures (typically hitting pointer)

- more efficient rebuild flow. ATM incremental rebuild is triggered when the
command needs that(i. e. it is global) while the commands that work on the
current source rebuild only it

Things missing in this PR:

- Documentation
- Extensive unit testing.

Although functional I still see this more as a POC that this approach can work.

Next steps:
- Implement `sug` request.
- Rework/extend the protocol to allow better client/server communication.
Ideally we will need push events, diagnostics should be restructored to allow
per file notifications, etc.
- implement v3 test suite.
- better logging

* Add tests for v3 and implement ideSug

* Remove typeInstCache/procInstCache cleanup

* Add ideChkFile command

* Avoid contains call when adding symbol info

* Remove log

* Remove segfaults

* Fixed bad cherry-pick resolve

* modulegraphs.dependsOn does not work on transitive modules

- make sure transitive deps are marked as dirty
capocasa pushed a commit to capocasa/Nim that referenced this pull request Mar 31, 2023
* Initial implementation of nimsuggest v3

Rework `nimsuggest` to use caching to make usage of ide commands more efficient.
Previously, all commands no matter what the state of the process is were causing
clean build. In the context of Language Server Protocol(LSP) and lsp clients
this was causing perf issues and overall instability. Overall, the goal of v3 is
to fit to LSP Server needs

- added two new commands:
  - `recompile` to do clean compilation
  - `changed` which can be used by the IDEs to notify that a particular file has been changed.
The later can be utilized when using LSP file watches.
  - `globalSymbols` - searching global references

- added `segfaults` dependency to allow fallback to clean build when incremental
fails. I wish the error to be propagated to the client so we can work on fixing
the incremental build failures (typically hitting pointer)

- more efficient rebuild flow. ATM incremental rebuild is triggered when the
command needs that(i. e. it is global) while the commands that work on the
current source rebuild only it

Things missing in this PR:

- Documentation
- Extensive unit testing.

Although functional I still see this more as a POC that this approach can work.

Next steps:
- Implement `sug` request.
- Rework/extend the protocol to allow better client/server communication.
Ideally we will need push events, diagnostics should be restructored to allow
per file notifications, etc.
- implement v3 test suite.
- better logging

* Add tests for v3 and implement ideSug

* Remove typeInstCache/procInstCache cleanup

* Add ideChkFile command

* Avoid contains call when adding symbol info

* Remove log

* Remove segfaults
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merge_when_passes_CI mergeable once green
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants