Skip to content

More precise completions and namespace member completions #1947

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

Merged
merged 10 commits into from
Oct 17, 2024

Conversation

minestarks
Copy link
Member

@minestarks minestarks commented Oct 3, 2024

Feature overview

This PR enables:

  1. Much more precise keyword completions where we only show the relevant syntax at a particular cursor location. For example:
within { } | 

At the cursor location indicated by |, we should only get the keyword apply .

  1. More precise completions for names where we take the syntactic context into account. For example:
operation Foo(x : | )

Here, we should only get type names.

  1. Namespace member completions. For example:
import Std.Diagnostics.|

The completions here should return only items that exist under Std.Diagnostics.

Code changes

Parser completions module

Introduce the completion module in the parser.

  • possible_words_at_offset_in_source - a new API to return completions at a particular offset . Uses the parser directly as the best source of knowledge about what tokens to expect.
  • Introduce the WordKinds flags to define the different kinds of word tokens that the parser can expect during parsing. (See compiler/qsc_parse/src/completion/word_kinds.rs for longer description)
  • See compiler/qsc_parse/src/completion/collector.rs for a description of how this all works.
  • Sprinkle expect()s at all possible locations in the parser where we expect a word.

Error recovery - AST changes

  • Introduce PathKind::Ok and PathKind::Err .
    • This new approach allows for a valid AST node to exist even when path parsing fails for a partial path. This is good for syntax such as "open Std." where we need:
      • The identifier nodes preceding . to be valid, so we can use them to look up possible completions.
      • The open statement to also be a valid node, so we can tell that the context requires a namespace (and not, say, a type name).
    • Most existing code will continue to only process valid paths.
  • Remove Idents struct and replace it with a trait implemented by various types such as Path and Ident slices. This should make the convenience methods easier to use without cloning in/out of the different types we need.

Error recovery - parser changes

  • Recovering struct parsing, so that e.g. new Foo. is still parsed as a valid struct expression node, allowing us to access the Foo ident from the AST
  • Recovering open statement parsing so that open Foo. can be recognized as an open item in the AST.

Language service

In language_service is essentially a complete rewrite of completions.rs, so I suggest reviewing the new code only and ditching the diff.

Other parser changes

  • Move implicit namespace parsing a bit so that it works better with the completion mechanism.
    • This also fixes the spurious "expected item, found eof" error when document only contains one token
  • Delete the dead path path_field_op
  • Add some missing keywords to item parsing recovery (export, import)

Other notes

  • Locals completions exclude imports from locals (they conflict with globals already added to completion) (fix in resolve.rs)
  • language-configuration.json : and removed wonky word pattern in playground and VS Code because we don't need it anymore now that we have proper . completions! Also update trigger characters.
  • Only include the samples snippets in empty documents, because now with the more concise completion list, it gets quite intrusive for them to show up at every word when typing code.
  • Update integration test to account for the fact that completions are more accurate now.

Not in this PR (coming next)

  • Struct and UDT field access completions.

@minestarks minestarks changed the title [DRAFT] Context-aware completions, namespace member completions, and other stories More precise completions and namespace member completions Oct 7, 2024
@minestarks minestarks marked this pull request as ready for review October 7, 2024 16:38
Copy link

github-actions bot commented Oct 7, 2024

Change in memory usage detected by benchmark.

Memory Report for 6fbbec5

Test This Branch On Main Difference
compile core + standard lib 17940700 bytes 17932132 bytes 8568 bytes

@minestarks
Copy link
Member Author

minestarks commented Oct 8, 2024

Change in memory usage detected by benchmark.

Memory Report for 6fbbec5

Test This Branch On Main Difference
compile core + standard lib 17940700 bytes 17932132 bytes 8568 bytes

I ran some tests to narrow it down. This increase is attributable entirely to the changes in the AST. A bunch of Path or Idents fields have been replaced with PathKind, a Span field has been added to ImportOrExportItem. It adds up to a net increase in memory.

I can't think of a way to shrink the AST any further, we are storing more information in there after all. So I think the 0.04% increase in memory usage is a worthwhile tradeoff for the feature.

@minestarks minestarks mentioned this pull request Oct 9, 2024
Copy link

Change in memory usage detected by benchmark.

Memory Report for c119d44

Test This Branch On Main Difference
compile core + standard lib 17945380 bytes 17936812 bytes 8568 bytes

Copy link

Change in memory usage detected by benchmark.

Memory Report for a9e7e76

Test This Branch On Main Difference
compile core + standard lib 17945380 bytes 17936812 bytes 8568 bytes

Copy link
Contributor

@ScottCarda-MS ScottCarda-MS left a comment

Choose a reason for hiding this comment

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

partially reviewed, will continue to review

@minestarks
Copy link
Member Author

@idavis found a bug:

Trying to complete

import QIR.in;

causes a panic since in is a keyword and that's a parse tree I did not expect to have to handle....

Working on the fix.

@minestarks
Copy link
Member Author

@idavis found a bug:

Trying to complete

import QIR.in;

causes a panic since in is a keyword and that's a parse tree I did not expect to have to handle....

Working on the fix.

Fixed with my latest commit.

Copy link

Change in memory usage detected by benchmark.

Memory Report for 96002f0

Test This Branch On Main Difference
compile core + standard lib 17945380 bytes 17936812 bytes 8568 bytes

@minestarks
Copy link
Member Author

Fixed with my latest commit.

Okay, I regressed things pretty badly with this fix, as @ScottCarda-MS discovered through testing (thanks!).

The following piece of code should produce a mostly valid AST (save for the error on line 3).

namespace Sample {
    operation BellStates() : (Result, Result)[] {
        Std.
        let bellStateTuples = [];

        for (label, prepare) in bellStateTuples {}
        return measurements;
    }

    /// doc comment
    operation PreparePhiPlus() : Unit {
    }
}

With my latest commit, there's no AST at all.

cc reviewers @idavis @swernli . I'm going to have to go back to the drawing board with the "keyword after dot" fix that handles QIR.in and similar paths. Expect more parser changes :/

@minestarks
Copy link
Member Author

I pushed what I think is my final update. The parser change to fix the last issue ended up being minimal!

Please sign off if no more concerns.

Copy link
Contributor

@ScottCarda-MS ScottCarda-MS left a comment

Choose a reason for hiding this comment

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

Discussed offline that the merge conflict is minor. Everything else looks good, and I tested out the feature manually.

Copy link

Change in memory usage detected by benchmark.

Memory Report for 145b6e6

Test This Branch On Main Difference
compile core + standard lib 17945380 bytes 17936812 bytes 8568 bytes

@minestarks minestarks enabled auto-merge October 17, 2024 18:25
@minestarks minestarks added this pull request to the merge queue Oct 17, 2024
Merged via the queue into main with commit 74c488b Oct 17, 2024
18 checks passed
@minestarks minestarks deleted the minestarks/member-completions branch October 17, 2024 18:39
github-merge-queue bot pushed a commit that referenced this pull request Oct 21, 2024
Builds on #1947 .

Enables:

1. Field access completions, for example:

```qsharp
let x = Complex(1.0, 2.0);
x.| 
```

At the cursor location indicated by `|`, completions should include
`Real` since it's a field of `Complex`.

2. Field assignment completions, for example:

```qsharp
struct Foo {
    bar: Int
}

new Foo { | }
```

Here, completions should include `Bar`.
github-merge-queue bot pushed a commit that referenced this pull request Nov 15, 2024
Fixing the behavior that regressed in #1947 when I was attempting to
limit samples to empty documents only.
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.

4 participants