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

+ added nimsuggest support for exception inlay hints #23202

Merged
merged 39 commits into from
Mar 15, 2024

Conversation

nickysn
Copy link
Contributor

@nickysn nickysn commented Jan 12, 2024

This adds nimsuggest support for displaying inlay hints for exceptions. An inlay hint is displayed around function calls, that can raise an exception, which isn't handled in the current subroutine (in other words, exceptions that can propagate back to the caller). On mouse hover on top of the hint, a list of exceptions that could propagate is shown.

The changes, required to support this are already commited to nimlangserver and the VS code extension. The extension and the server allow configuration for whether these new exception hints are enabled (they can be enabled or disabled independently from the type hints), as well as the inlay strings that are inserted before and after the name of the function, around the function call. Potentially, one of these strings can be empty, for example, the user can choose to add an inlay hint only before the name of the function, or only after the name of the function.

@@ -55,10 +55,12 @@ type
concreteTypes*: seq[FullId]
inst*: PInstantiation

SymInfoPair* = object
SymInfoPair* = ref object
Copy link
Member

Choose a reason for hiding this comment

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

Does it really need to be ref? The compiler suffers from a massive overuse of ref making things harder to understand than necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

How do we set caughtExceptions then? This is done in a different pass, after the SymInfoPair objects have been collected. Then, we need to update them, by setting caughtExceptions. If it's not a ref object, we should copy the entire object, change a single field, then copy it again? Isn't that worse than using a 'ref object'? Or, is there an easier way?

Copy link
Member

Choose a reason for hiding this comment

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

Why not update it in-place or move the object?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok: 9ff6cd9

except ValueError:
echo "Error parsing int: " & a
echo outp.readAll()
raise
Copy link
Member

Choose a reason for hiding this comment

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

What does that do? Improve the error message but does not handle the error (it uses re-raising)? But who had problems with the previous error message?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

During the development of this feature, I had a nimsuggest crash that only happened on the GitHub CI machines, which I could not reproduce on my computer. Therefore, I added this, so that the stack trace, produced by nimsuggest is printed on the screen, and becomes visible in the GitHub CI log. The bug, that caused the crash has been fixed, but I left this here, because it's useful for diagnostic purposes, even though it's unrelated to the inlay hints for exceptions. I can extract it to a separate PR if you want?

Copy link
Member

Choose a reason for hiding this comment

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

Ideally you simply remove it as I don't like it. If you want a better/different error mesage handle the error completely aka replace the raise by quit.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done: a7bf527

proc add*(s: var SuggestSymbolDatabase; v: SymInfoPair) =
s.mgetOrPut(v.info.fileIndex, newSuggestFileSymbolDatabase()).add(v)

proc findSymInfo*(s: var SuggestFileSymbolDatabase; li: TLineInfo): ref SymInfoPair =
Copy link
Member

Choose a reason for hiding this comment

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

Why not use ptr SymInfoPair?

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 saw that other functions in nimsuggest.nim return ref SymInfoPair - findSymData, findByTLineInfo, so I used ref for consistency. Is using ptr the preferred way? Should the other functions that return ref SymInfoPair also be changed to ptr SymInfoPair?

Copy link
Member

Choose a reason for hiding this comment

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

If possible, yes. We don't wrap types with ref just so that we can get nil as a possible value. We use ptr for that. Of course, you need to watch out things are still memory safe but it's usually the case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed the result to ptr in findSymInfo: 6a22c4a
Should I change the others here, or should that be in a separate PR?

var idx = binarySearch(s.items, q, cmp)
if idx != -1:
new(result)
result[] = s.items[idx]
Copy link
Member

Choose a reason for hiding this comment

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

Why not use result = addr s.items[idx]?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done: 6a22c4a

@Araq
Copy link
Member

Araq commented Jan 29, 2024

How does this affect the memory consumption of nimsuggest?

@nickysn
Copy link
Contributor Author

nickysn commented Jan 29, 2024

How does this affect the memory consumption of nimsuggest?

I hope the memory use won't increase much, but this needs to be measured. I'll try to do some measurements and report what I found.

@nickysn
Copy link
Contributor Author

nickysn commented Jan 29, 2024

How does this affect the memory consumption of nimsuggest?

I hope the memory use won't increase much, but this needs to be measured. I'll try to do some measurements and report what I found.

Ok, I measured the memory use of nimsuggest on two files - nimsuggest.nim (an example of a large-sized project, as it includes the Nim compiler) and nimlangserver.nim (a medium-sized project). I used smem -k to measure the memory use. I'm running the tests on Fedora 39 for x86_64. I compared nimsuggest from this feature branch with nimsuggest from the devel branch, after synchronizing this branch with the devel branch. The results:

nimsuggest.nim:
before:
PID User Command Swap USS PSS RSS
42451 nickysn nimsuggest /home/nickysn/tr 0 550.8M 550.8M 552.8M
after:
PID User Command Swap USS PSS RSS
45030 nickysn nimsuggest /home/nickysn/tr 0 591.8M 591.8M 593.7M

That's about 7.4% increase.

nimlangserver.nim:
before:
PID User Command Swap USS PSS RSS
43033 nickysn nimsuggest /home/nickysn/wo 0 219.4M 219.4M 221.4M
after:
PID User Command Swap USS PSS RSS
45588 nickysn nimsuggest /home/nickysn/wo 0 278.5M 278.5M 280.4M

That's about 26% increase.

I'm a little surprised that we get a larger increase (percentage-wise) on smaller projects, compared to large projects. I would expect it to be the opposite. Maybe it's an artifact of the measurement method or the way the heap is managed (how it grows)?

@nickysn nickysn closed this Jan 29, 2024
@nickysn nickysn reopened this Jan 29, 2024
@Araq
Copy link
Member

Araq commented Jan 30, 2024

Can be this made opt-in somehow? Not everybody enjoys a nimsuggest that uses more memory just so that it reports exception tracking details which many don't care about.

@nickysn
Copy link
Contributor Author

nickysn commented Jan 30, 2024

Can be this made opt-in somehow? Not everybody enjoys a nimsuggest that uses more memory just so that it reports exception tracking details which many don't care about.

I'm thinking about this. Meanwhile I've commited a small optimization that makes the memory increase slightly less. Now it's:
for nimsuggest.nim:
286965 nickysn nimsuggest /home/nickysn/tr 0 590.4M 590.4M 592.5M
That's a 7.2% increase (previously, it was 7.4%).

for nimlangserver.nim:
287981 nickysn nimsuggest /home/nickysn/wo 0 256.9M 258.4M 262.0M
That's a 17% increase (previously, it was 26%).

It's still not opt-in. I'm still thinking about how to optimize this SymInfoPair structure. Since it's so critical, there are a lot of optimizations possible if it's redesigned, however these changes would probably be unrelated to the exception hints.

@nickysn
Copy link
Contributor Author

nickysn commented Jan 30, 2024

One way to make this opt-in is to move the caught exceptions data to a parallel array (in other words, to partially move from an array of structs to a structure of arrays). This way, if exception hints are turned off, we can avoid allocating the extra memory. If there are no better suggestions, and if I don't come with a better solution, I'll try to implement this approach.

@Araq
Copy link
Member

Araq commented Jan 31, 2024

Ok, let's see how this outline solution of yours looks like.

…ains

  caughtExceptions as a separate array. This will allow for the memory for
  caughtExceptions not to be allocated, when the exception inlay hints are not
  enabled (which is not done, yet). Many things are refactored to allow
  converting SuggestFileSymbolDatabase from an array of structs, to a struct of
  arrays. Extracting further fields as separate arrays will result in further
  reduction of used memory, even when inlay hints for exceptions are turned off,
  since the SymInfoPair structure wastes too much memory, due to alightment
  padding.
…ce wasted

  memory, due to padding (this will actually happen in the next commit, when
  isDecl is moved as well).
* fixed the commented out setting of caughtExceptionsSet that was temporarily
  disabled in the previous commit
@nickysn nickysn reopened this Feb 11, 2024
…n (versus

  the previous column) inside getTokenLenFromSource
@nickysn nickysn closed this Feb 12, 2024
@nickysn nickysn reopened this Feb 12, 2024
@nickysn nickysn closed this Feb 12, 2024
@nickysn nickysn reopened this Feb 12, 2024
@Araq
Copy link
Member

Araq commented Mar 15, 2024

Move SuggestSymbolDatabase and its related procs into its own module.

@nickysn
Copy link
Contributor Author

nickysn commented Mar 15, 2024

Move SuggestSymbolDatabase and its related procs into its own module.

Done: 00f6d55

@Araq Araq merged commit 899ba01 into nim-lang:devel Mar 15, 2024
19 checks passed
Copy link
Contributor

Thanks for your hard work on this PR!
The lines below are statistics of the Nim compiler built from 899ba01

Hint: mm: orc; opt: speed; options: -d:release
178414 lines; 8.234s; 753.07MiB peakmem

@SirOlaf
Copy link
Contributor

SirOlaf commented Mar 15, 2024

This seems to have some issues inferring exceptions of generic procs.

proc foo[T](x: T) =
  discard

foo(1)

A bell for the call foo(1) appears, supposedly raising "Exception".
I am unsure if this a new issue or if this simply exposes an existing one.
Looks like exceptions from generic procs didn't propagate properly before either, but this makes it obvious by putting Exception and inserting bells everywhere.

Removing the getEbase call in initialization here https://github.com/nim-lang/Nim/pull/23202/files#diff-a7c8d25cefdf0d3b4d7713ada23b1ec76416139cdaaa9999c0e8ef8fda94cb2aR931 gets rid of some false positives but then it simply thinks generics never raise.

Issue is that the symbol table holds the generic variant instead of an instance, so propagation still works as it happens in sempass2, but the immediate ide hint is complete nonsense.

@nickysn nickysn deleted the try_inlay_hint5 branch March 18, 2024 20:11
nickysn added a commit to nickysn/Nim that referenced this pull request Mar 18, 2024
This adds nimsuggest support for displaying inlay hints for exceptions.
An inlay hint is displayed around function calls, that can raise an
exception, which isn't handled in the current subroutine (in other
words, exceptions that can propagate back to the caller). On mouse hover
on top of the hint, a list of exceptions that could propagate is shown.

The changes, required to support this are already commited to
nimlangserver and the VS code extension. The extension and the server
allow configuration for whether these new exception hints are enabled
(they can be enabled or disabled independently from the type hints), as
well as the inlay strings that are inserted before and after the name of
the function, around the function call. Potentially, one of these
strings can be empty, for example, the user can choose to add an inlay
hint only before the name of the function, or only after the name of the
function.

(cherry picked from commit 899ba01)
nickysn added a commit to nickysn/Nim that referenced this pull request Mar 18, 2024
This adds nimsuggest support for displaying inlay hints for exceptions.
An inlay hint is displayed around function calls, that can raise an
exception, which isn't handled in the current subroutine (in other
words, exceptions that can propagate back to the caller). On mouse hover
on top of the hint, a list of exceptions that could propagate is shown.

The changes, required to support this are already commited to
nimlangserver and the VS code extension. The extension and the server
allow configuration for whether these new exception hints are enabled
(they can be enabled or disabled independently from the type hints), as
well as the inlay strings that are inserted before and after the name of
the function, around the function call. Potentially, one of these
strings can be empty, for example, the user can choose to add an inlay
hint only before the name of the function, or only after the name of the
function.

(cherry picked from commit 899ba01)
@arnetheduck
Copy link
Contributor

Looks like exceptions from generic procs didn't propagate properly before either

I guess that's the conservative choice - you can't know which exceptions will be raised until you instantiate it - when is the most trivial way (but consider calling an overloaded function from foo):

proc foo[T](x: T) =
  when T is int: raise ValueError 
  else: raise OSError

foo(1)

@SirOlaf
Copy link
Contributor

SirOlaf commented Mar 25, 2024

It propagates without issues in the sempass2 step of compiler, nimsuggest does not get the instance symbol and that is what fails. I tried hacking together a fix to demonstrate this in #23414
Should work normally if that is fixed properly.

narimiran pushed a commit that referenced this pull request May 21, 2024
This adds nimsuggest support for displaying inlay hints for exceptions.
An inlay hint is displayed around function calls, that can raise an
exception, which isn't handled in the current subroutine (in other
words, exceptions that can propagate back to the caller). On mouse hover
on top of the hint, a list of exceptions that could propagate is shown.

The changes, required to support this are already commited to
nimlangserver and the VS code extension. The extension and the server
allow configuration for whether these new exception hints are enabled
(they can be enabled or disabled independently from the type hints), as
well as the inlay strings that are inserted before and after the name of
the function, around the function call. Potentially, one of these
strings can be empty, for example, the user can choose to add an inlay
hint only before the name of the function, or only after the name of the
function.

(cherry picked from commit 899ba01)
narimiran pushed a commit that referenced this pull request May 21, 2024
This adds nimsuggest support for displaying inlay hints for exceptions.
An inlay hint is displayed around function calls, that can raise an
exception, which isn't handled in the current subroutine (in other
words, exceptions that can propagate back to the caller). On mouse hover
on top of the hint, a list of exceptions that could propagate is shown.

The changes, required to support this are already commited to
nimlangserver and the VS code extension. The extension and the server
allow configuration for whether these new exception hints are enabled
(they can be enabled or disabled independently from the type hints), as
well as the inlay strings that are inserted before and after the name of
the function, around the function call. Potentially, one of these
strings can be empty, for example, the user can choose to add an inlay
hint only before the name of the function, or only after the name of the
function.

(cherry picked from commit 899ba01)
narimiran pushed a commit that referenced this pull request May 24, 2024
This adds nimsuggest support for displaying inlay hints for exceptions.
An inlay hint is displayed around function calls, that can raise an
exception, which isn't handled in the current subroutine (in other
words, exceptions that can propagate back to the caller). On mouse hover
on top of the hint, a list of exceptions that could propagate is shown.

The changes, required to support this are already commited to
nimlangserver and the VS code extension. The extension and the server
allow configuration for whether these new exception hints are enabled
(they can be enabled or disabled independently from the type hints), as
well as the inlay strings that are inserted before and after the name of
the function, around the function call. Potentially, one of these
strings can be empty, for example, the user can choose to add an inlay
hint only before the name of the function, or only after the name of the
function.

(cherry picked from commit 899ba01)
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

Successfully merging this pull request may close these issues.

None yet

5 participants