-
Notifications
You must be signed in to change notification settings - Fork 257
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
feat: Provide formals and declarations type highlighting. #1630
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this improvement since it's sometimes useful to see what type the compiler infers.
I prefer that we stick to SingleOrDefault
since for the lookup there must not be any overlapping ranges because a designator should not have multiple lookup entries.
Moreover, please add a new test for the now supported Formal
lookup.
var symbolsAtPosition = LookupTree.Query(position); | ||
// TODO: Figure out why duplication crashes SingleOrDefault before using FirstOrDefault | ||
// Use case: function f(a: int) {}, and hover over a. | ||
symbol = symbolsAtPosition.FirstOrDefault(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since there should only be one LookUp
entry per designator, one designator is registered twice or overlaps with the range of another.
This should be fixed as this probably hides another error.
Thank you for letting me know how much it was important to keep |
I did not find documentation about how to run the tests in DafnyLanguageServer.Test |
Removed autogenerated expressions from analysis
I'm sorry that I haven't documented this yet. I tend not to document things that are standard for the utilized platform. That was the same for the VSCode extension until Robin asked for documentation. You can either test it through the IDE. For example, in Visual Studio you can open the Test Explorer view: Alternatively, you can execute the tests through the command line: dotnet test .\Source\DafnyLanguageServer.Test\DafnyLanguageServer.Test.csproj It's important to note that you may have to place z3 in the build directory of the tests. That's |
Thanks for these instructions. I think they are relevant to any new user so that I added them in the wiki |
Fixed function body hovering. ComprehensionSymbol is now a ScopeSymbol
Support for scopes in method and function specifications.
This PR is ready for review @camrein . Nothing new specific on my agenda. I did many upgrades in the highlighting system (see updated PR message) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a great improvement.
I haven't fully reviewed it since I have the feeling some changes might be irrelevant.
In general, the language server does not have any abbreviations so I'd prefer to keep this style. I have seen some things that would need improvement (probably in another PR) to make the design choices a bit more clear.
Feel free to tag me once you've included my suggested changes (note: I haven't marked everything since there are some repetitions of the same pattern).
Source/DafnyLanguageServer/Language/Symbols/ComprehensionSymbol.cs
Outdated
Show resolved
Hide resolved
Source/DafnyLanguageServer/Language/Symbols/DafnyLangSymbolResolver.cs
Outdated
Show resolved
Hide resolved
Source/DafnyLanguageServer/Language/Symbols/DafnyLangSymbolResolver.cs
Outdated
Show resolved
Hide resolved
Source/DafnyLanguageServer/Language/Symbols/DafnyLangSymbolResolver.cs
Outdated
Show resolved
Hide resolved
Source/DafnyLanguageServer/Language/Symbols/DafnyLangSymbolResolver.cs
Outdated
Show resolved
Hide resolved
- Groupped LetExpr and ComprehensionExpr in a single interface for accessing bound variables - Added test case for result variable in functions + implemented it - New overloads for every type of comprehension expression + simplifications. - Fixed CI warnings about potential null initalization - Removed abbreviations - Moved AsEnumerable from Symbol to SymbolExtensions - Removed obsolete TODO
…ub.com/dafny-lang/dafny into ide-highlight-formals-and-declarations
…rn type which cause symbol building to crash. Fixed potential errors with null tokens
Fail-safe but debuggable TryGetSymbolAt.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for these improvements. This looks way better now.
Source/DafnyLanguageServer/Language/Symbols/DafnyLangSymbolResolver.cs
Outdated
Show resolved
Hide resolved
Source/DafnyLanguageServer/Language/Symbols/DafnyLangSymbolResolver.cs
Outdated
Show resolved
Hide resolved
Source/DafnyLanguageServer/Language/Symbols/SymbolTableFactory.cs
Outdated
Show resolved
Hide resolved
Source/DafnyLanguageServer/Language/Symbols/SymbolTableFactory.cs
Outdated
Show resolved
Hide resolved
- Use of pattern matching - Warning logging if duplicate symbol in lookup table - Adding to list of symbol instead of replacing the initialized list - Better naming of start and end token for scope symbol - Removed a canceled refactoring artefact (IToken? => IToken) - Removed extra whitespace -
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great so far. I've only had some minor input now. Thanks for taking your time.
Source/DafnyLanguageServer/Language/Symbols/DafnyLangSymbolResolver.cs
Outdated
Show resolved
Hide resolved
Source/DafnyLanguageServer/Language/Symbols/DafnyLangSymbolResolver.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great, thanks!
Since I might be biased by now, @keyboardDrummer would you mind giving a second look?
Source/DafnyLanguageServer/Language/Symbols/DafnyLangSymbolResolver.cs
Outdated
Show resolved
Hide resolved
Source/DafnyLanguageServer/Language/Symbols/DafnyLangSymbolResolver.cs
Outdated
Show resolved
Hide resolved
Source/DafnyLanguageServer/Language/Symbols/SymbolTableFactory.cs
Outdated
Show resolved
Hide resolved
@@ -265,8 +266,9 @@ public class BuiltIns { | |||
/// the built-in total-arrow type (if "total", in which case "member" is expected to denote the "requires" member). | |||
/// The given "id" is expected to be already resolved. | |||
/// </summary> | |||
private Expression ArrowSubtypeConstraint(IToken tok, BoundVar id, Function member, List<TypeParameter> tps, bool total) { | |||
private Expression ArrowSubtypeConstraint(IToken tok, IToken endTok, BoundVar id, Function member, List<TypeParameter> tps, bool total) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we not use the IRegion
interface here so we only need a single parameter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The two places in which this ArrowSubtypeConstraint
is being called actually give Token.NoToken
as argument, so there is nothing close to IRegion
to provide, so although this is a good suggestion, it's better to keep it this way until there is a compelling reason to change it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not wrap the Tokens in a class Region : IRegion
? I think it's common for AST nodes to know their start and end token, and to store both in a single object. Why have two parameters when you can have one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After 1-1 discussion, we agreed that, since Expressions already use tok
for the start token, it's better to leave this huge refactoring for an independent PR later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We will eventually add start and end positions for every expression in Dafny's grammar, so it's not useful to do this change now in a way that would be half-baked.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the ping, I had a quick look. I'm not sure when the right time is to change the way end tokes are passed, but here's my 2¢:
- Are these tokens used for anything else than position reporting? If not, they shouldn't even be passed into the various AST constructors, and only ranges instead. It's OK to implement a range variant that's based on a pair of tokens if we really want to keep the tokens around for some reason.
- Exposing a pair of tokens directly is a risky business, because it's unclear (at least to me) what the semantics of end tokens are. For example when you convert to a range you use
GetLSPPosition
on both tokens, but that means the range ends on the beginning of the last token. If the last token is part of the range, the range should end at the end of that token instead. If the current code is right, then I expect others will make the same mistake as I did when proofreading this, so I think there's value in a level of indirection that encapsulates pairs of tokens and exposes a range. - I have no thoughts on when that change should be done. It would be OK to me to put a FIXME in there, but I don't know the context of this change.
HTH!
(Also, I props to you on completing that change; it's impressive me how complicated this conceptually simple change ended up being, so nice job on pushing it through — and the final feature is very cool.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no thoughts on when that change should be done. It would be OK to me to put a FIXME in there, but I don't know the context of this change.
Do we all to agree that the desirable end state is for every expression AST Node to have a Range/Region field instead of a token field? I don't think there is a reason to work with tokens after parsing.
Given that end state, why make a detour by first introducing a second token field to expression AST nodes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we all agree on the final state.
It's not a detour, it's actually reusing the same field name and interface as the statements, i.e. being consistent with the system already in place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's actually reusing the same field name and interface as the statements, i.e. being consistent with the system already in place.
Okay, let's settle with that then.
@MikaelMayer thanks for applying my suggested changes and explaining to me some of your decisions. |
new Range(scopeSymbol.Declaration.Tok.GetLspPosition(), scopeSymbol.Declaration.EndTok.GetLspPosition()) | ||
scopeSymbol.BodyStartToken, | ||
scopeSymbol.BodyStartToken.GetLspRange(), | ||
new Range(scopeSymbol.BodyStartToken.GetLspPosition(), endToken.GetLspPosition()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't you want ToLspPosition(token.line, token.col + token.val.Length)
here? (as in GetLspRange?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I've added details about this above; copied here for context:)
It's unclear to me what the semantics of end tokens are. For example when you convert to a range you use GetLSPPosition on both tokens, but that means the range ends on the beginning of the last token. If the last token is part of the range, the range should end at the end of that token instead.
I added hovering type annotations to formals (in parameters)
and out parameters
Local variable declarations.
Bound variables in set comprehensions
Bound variables in forall expressions
Bound variables in exists expressions
Bound variables in map comprehensions
Bound variables in lambdas
By method bodies in functions
Let expressions:
Note that not only this adds hovering annotations, but it also adds the ability to jump to the definition for all variables declared in set and map comprehensions, forall and exists expressions, and let expressions, using either the right-click menu or CTRL+click on the variable.
Previously, hovering such variables either at declaration sites or even on their use site (for comprehensions) did not show any hint about their type, even in specifications.
The reason why this is useful is that it removes the need to investigate a method call's signature to know what is the type of a variable that is declared and assigned at the same time, and for formals for consistency.