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

Bug Report: Code completion when implementing functions in VSCode doesn't work properly. #11467

Closed
CalinZBaenen opened this issue Feb 13, 2022 · 22 comments · Fixed by #11967
Closed
Labels
A-completion autocompletion A-lsp LSP conformance issues and missing features C-bug Category: bug E-unknown It's unclear if the issue is E-hard or E-easy without digging in

Comments

@CalinZBaenen
Copy link

Specs.

In Visual Studio Code, I have suspicion that Rust Analyzer's code completion isn't working as intended.
Here's some specs:

Rust-Analyzer Version: 7a17fb9c4 2022-02-13 nightly
RustUp Version: rustup 1.24.3 (2021-11-09)
RustC Version: rustc 1.58.1 (db9d1b20b 2022-01-20)

VSCode Version: 1.64.0, 5554b12acf27056905806867f251c859323ff7e9, x64
Enabled VSCode Extensions: "Rust Analyzer", "GitLens"
VSCode Vendor: 

Operating System: Arch (x86_64)
Desktop Environment: XFCE4

Description.

As far as I can tell, only one prediction (pattern) doesn't work, though, similar bugs may be present in other forms.
Whenever I try to implement a trait onto a datatype I have (for this example's purposes Trait onto S*), when implementing the functions in Trait, no predictions come up when I start writing "fn " (with a space at the end); even if I add the first letter(s) of a function name.

Reproduction.

Example:

trait Trait {
  fn test() -> String;
}

struct S;
impl Trait for S {
  // I START WRITING HERE...
}

When I replace // I START WRITING HERE... with fn t, with my cursor and focus still in the textarea of VSCode, no predictions pop up.
However, instead of writing fn t, if I just start writing te; for example, then the prediction fn test() -> String comes up. (Even though it should work in only the former OR both scenarios.)

I can tell it's not strictly a VSCode bug, because when I do Ctrl + Space, I'm told "No suggestions.".

Working Example.

This bug came up while I was working on my game RuntDeale.
I had a trait, Positioned, in position.rs. After using Positioned in sprites.rs (sibling of position.rs), I was implementing Positioned for Sprite<'_, T> (specific implementation details not important*).
This is the point I found the bug, entering the impl block, typing away, noticing fn se didn't trigger the completion for fn setX(&mut self, x:Scalar) -> ().

Temporary Workaround.

There is an "assist" that's provided, nicked "Implement Missing Members", which works fine.
But it implements everything at once, which is overwhelming for me. - I usually work on each function one at a time.

Exception.

This bug is not apparent in at-least one setup, in NioVim, according to testimonial @olestrohm:
Testimony of the bug.

@Veykril
Copy link
Member

Veykril commented Feb 14, 2022

Might be caused by #11412 and us hitting some specific behaviour in VSCode.
There is this comment here: https://github.com/rust-analyzer/rust-analyzer/blob/7a17fb9c43b2cd0a8a2ff3d93b9d436fa28153d6/crates/ide_completion/src/item.rs#L26-L34
which might play into this

@Veykril Veykril added the A-completion autocompletion label Feb 14, 2022
@flodiebold
Copy link
Member

I can reproduce it in Emacs as well.

@CalinZBaenen
Copy link
Author

@flodiebold, have you been having this issue, or did you just reproduce it?
And do you know how I can get into a fixed state (seeing as this isn't a VSCode specific issue, and may be resolvable without further study)?

@flodiebold
Copy link
Member

I'm not sure what you're asking; 'reproduce' means I have the same issue when I try it. It's a bug that needs to be fixed.

@CalinZBaenen
Copy link
Author

@flodiebold, essentially what I asked was if the bug was occurring naturally for you, or if you had to do any proceeding steps to get it to (not) work.
From your response, it seems like the former.

@Lokathor
Copy link

I've hit this several times when trying to fill in trait methods in the last few days. I haven't particularly noticed an issue with other completions, though they may also be affected.

@Veykril Veykril added C-feature Category: feature request C-bug Category: bug E-unknown It's unclear if the issue is E-hard or E-easy without digging in and removed C-feature Category: feature request labels Feb 19, 2022
@Veykril
Copy link
Member

Veykril commented Feb 19, 2022

This does look like we are breaking the LSP somewhere as the server does send a proper completion response here.

https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#completionItem

	 * *Note:* The range of the edit must be a single line range and it must
	 * contain the position at which completion has been requested.

Yep our response is invalid.
So we need to split up our edits here to make use of the additionalTextEdits field here to fill in the following lines of the completion somehow.

@Veykril Veykril added the A-lsp LSP conformance issues and missing features label Feb 19, 2022
@CalinZBaenen
Copy link
Author

@Veykril, can you explain what that means in laymans terms? - I wanna understand the issue, but idk the jargon.

@Veykril
Copy link
Member

Veykril commented Feb 19, 2022

We currently send a completion with one text edit that replaces the text range at from fn keyword to cursor position with a replacement text that spans multiple lines(contains newlines). This is against the language server protocol, we need change this so that we only send a replacement with a single line in the main text edit, and add the followings lines to the additionalTextEdits as insertions.

@CalinZBaenen
Copy link
Author

@Veykril, what's the status of the bug?

@Veykril
Copy link
Member

Veykril commented Mar 1, 2022

Same as stated in the previous message, we still violate the LSP which makes clients discard our completion.

@jonas-schievink
Copy link
Contributor

Note that this happens not just with fn $0, but with all associated items, even if the resulting completion only modifies a single line:

trait Tr {
    const KONST: u8;
}

impl Tr for () {
    const $0
}

For this, we send the following LSP CompletionItem:

[crates/rust-analyzer/src/to_proto.rs:318] lsp_item = CompletionItem {
    label: "const KONST: u8 =",
    label_details: None,
    kind: Some(
        Constant,
    ),
    detail: None,
    documentation: None,
    deprecated: Some(
        false,
    ),
    preselect: Some(
        true,
    ),
    sort_text: Some(
        "ffffffef",
    ),
    filter_text: Some(
        "KONST",
    ),
    insert_text: None,
    insert_text_format: None,
    insert_text_mode: None,
    text_edit: Some(
        InsertAndReplace(
            InsertReplaceEdit {
                new_text: "const KONST: u8 = ",
                insert: Range {
                    start: Position {
                        line: 5,
                        character: 4,
                    },
                    end: Position {
                        line: 5,
                        character: 10,
                    },
                },
                replace: Range {
                    start: Position {
                        line: 5,
                        character: 4,
                    },
                    end: Position {
                        line: 5,
                        character: 10,
                    },
                },
            },
        ),
    ),
    additional_text_edits: Some(
        [],
    ),
    command: None,
    commit_characters: None,
    data: None,
    tags: None,
}

bors bot added a commit that referenced this issue Apr 12, 2022
11967: fix: Fix trait impl completions not triggering after `fn`/`const`/`type` r=jonas-schievink a=jonas-schievink

![screenshot-2022-04-12-17:13:01](https://user-images.githubusercontent.com/1786438/162996087-56540f5e-a6be-4111-a4a5-8de21f483a5e.png)

Fixes #11467
cc #11860

bors r+

Co-authored-by: Jonas Schievink <jonas.schievink@ferrous-systems.com>
bors bot added a commit that referenced this issue Apr 12, 2022
11967: fix: Fix trait impl completions not triggering after `fn`/`const`/`type` r=jonas-schievink a=jonas-schievink

![screenshot-2022-04-12-17:13:01](https://user-images.githubusercontent.com/1786438/162996087-56540f5e-a6be-4111-a4a5-8de21f483a5e.png)

Fixes #11467
cc #11860

bors r+

Co-authored-by: Jonas Schievink <jonas.schievink@ferrous-systems.com>
@bors bors bot closed this as completed in #11967 Apr 12, 2022
@tgmerritt
Copy link

tgmerritt commented Jun 6, 2022

I see the fix previously, but I'm experiencing exactly this issue. Have spent an hour on various posts to no avail. What commands can I run to get you the details you need to further debug?

image

Explanations appear which is a feature of the LSP I guess, but completion does not trigger.

image

Settings are enabled as far as I can tell. I'm currently on the rust-analyzer pre-release version v0.4.1082 as of this message.

I don't know that it makes any difference, but I frequently switch languages within VS Code, and my settings are tied to User instead of Workspace, if there is potentially a conflict where one setting is overriding another, such as a default LSP setting as opposed to a language-specific LSP setting, please provide some guidance on how I would locate that info to help.

@flodiebold
Copy link
Member

Your screenshot and description doesn't look like you're experiencing the bug described here. Can you open a new issue, and describe in more detail what you're doing and what you're expecting to happen?

@tgmerritt
Copy link

tgmerritt commented Jun 6, 2022

Your screenshot and description doesn't look like you're experiencing the bug described here. Can you open a new issue, and describe in more detail what you're doing and what you're expecting to happen?

Before opening a new issue, let me state that what I'm doing is typing fn or fn name and expecting the auto-completion capability to suggest a function (with brackets, spacing, etc.) so that I can develop more quickly and accurately.

The OP of this issue describes this exact phenomenon:

When I replace // I START WRITING HERE... with fn t, with my cursor and focus still in the textarea of VSCode, no predictions pop up.

That is precisely what is happening. No predictions pop up entries where I expect code completion.

If you still feel this is a separate issue, I would be happy to open a new issue to track. But OP's description of their experience and my experience are identical as far as I can tell.

@flodiebold
Copy link
Member

flodiebold commented Jun 6, 2022

Your screenshot does not show you typing fn. Can you provide the context (source file) where you're expecting completions, or are you trying the exact example from the original issue? If the latter, do you get completions if you start typing the function name like in the original issue?

@tgmerritt
Copy link

Here is a screenshot of the issue in action:

image

Here is the full contents of the code as it is currently:

fn another_function(val: i32, label: char) {
    println!("The value of x is {}{}", val, label);
}

fn five() -> i32 {
    5
}

fn t // <== cursor is right here, neither with the 't' nor without do I get any code completion, tried all manner of name, minimum character input, etc.  Nothing results in a proposed completion

fn main() {
    let condition = true;
    let number = if condition { 5 } else { "six" };

    println!("The value of number is: {}", number);
}

I would like to be able to find some log where the call from VS Code is made to the code completion service, as there must be some logging statement that would show the issue. Do you know how I could grab that output?

@flodiebold
Copy link
Member

There is currently no completion in that position. The completions this bug is about only happen when implementing a trait. There is a snippet for fn though, so if you press enter on the fn suggestion you'll get the () {} automatically and can jump between function name, parameters and body.

@tgmerritt
Copy link

Hi @flodiebold - I created a video to demonstrate what I'm seeing and what I'm expecting - if you see this and determine it's a separate issue, I will open a separate issue.

https://www.loom.com/share/b15192081e6044358eade1e1a0c5c720

At the end of the video, I show a bit of backtrace, I've pasted the entire output here:

thread 'Worker' panicked at 'Bad offset: range 0..39 offset 52', /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/rowan-0.15.4/src/cursor.rs:751:9
Panic context:
> 
version: ad6810e90 2022-06-06 nightly
request: textDocument/codeAction CodeActionParams {
    text_document: TextDocumentIdentifier {
        uri: Url {
            scheme: "file",
            cannot_be_a_base: false,
            username: "",
            password: None,
            host: None,
            port: None,
            path: "/Users/tyler/Software_Development/rust_tutorials/functions/src/main.rs",
            query: None,
            fragment: None,
        },
    },
    range: Range {
        start: Position {
            line: 4,
            character: 13,
        },
        end: Position {
            line: 4,
            character: 13,
        },
    },
    context: CodeActionContext {
        diagnostics: [
            Diagnostic {
                range: Range {
                    start: Position {
                        line: 4,
                        character: 13,
                    },
                    end: Position {
                        line: 4,
                        character: 13,
                    },
                },
                severity: Some(
                    Error,
                ),
                code: Some(
                    String(
                        "syntax-error",
                    ),
                ),
                code_description: Some(
                    CodeDescription {
                        href: Url {
                            scheme: "https",
                            cannot_be_a_base: false,
                            username: "",
                            password: None,
                            host: Some(
                                Domain(
                                    "rust-analyzer.github.io",
                                ),
                            ),
                            port: None,
                            path: "/manual.html",
                            query: None,
                            fragment: Some(
                                "syntax-error",
                            ),
                        },
                    },
                ),
                source: Some(
                    "rust-analyzer",
                ),
                message: "Syntax Error: expected a name",
                related_information: None,
                tags: None,
                data: None,
            },
            Diagnostic {
                range: Range {
                    start: Position {
                        line: 4,
                        character: 13,
                    },
                    end: Position {
                        line: 4,
                        character: 13,
                    },
                },
                severity: Some(
                    Error,
                ),
                code: Some(
                    String(
                        "syntax-error",
                    ),
                ),
                code_description: Some(
                    CodeDescription {
                        href: Url {
                            scheme: "https",
                            cannot_be_a_base: false,
                            username: "",
                            password: None,
                            host: Some(
                                Domain(
                                    "rust-analyzer.github.io",
                                ),
                            ),
                            port: None,
                            path: "/manual.html",
                            query: None,
                            fragment: Some(
                                "syntax-error",
                            ),
                        },
                    },
                ),
                source: Some(
                    "rust-analyzer",
                ),
                message: "Syntax Error: expected function arguments",
                related_information: None,
                tags: None,
                data: None,
            },
            Diagnostic {
                range: Range {
                    start: Position {
                        line: 4,
                        character: 13,
                    },
                    end: Position {
                        line: 4,
                        character: 13,
                    },
                },
                severity: Some(
                    Error,
                ),
                code: Some(
                    String(
                        "syntax-error",
                    ),
                ),
                code_description: Some(
                    CodeDescription {
                        href: Url {
                            scheme: "https",
                            cannot_be_a_base: false,
                            username: "",
                            password: None,
                            host: Some(
                                Domain(
                                    "rust-analyzer.github.io",
                                ),
                            ),
                            port: None,
                            path: "/manual.html",
                            query: None,
                            fragment: Some(
                                "syntax-error",
                            ),
                        },
                    },
                ),
                source: Some(
                    "rust-analyzer",
                ),
                message: "Syntax Error: expected a block",
                related_information: None,
                tags: None,
                data: None,
            },
        ],
        only: None,
    },
    work_done_progress_params: WorkDoneProgressParams {
        work_done_token: None,
    },
    partial_result_params: PartialResultParams {
        partial_result_token: None,
    },
}

thread 'Worker' panicked at 'Bad offset: range 0..39 offset 52', /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/rowan-0.15.4/src/cursor.rs:751:9
   0: _rust_begin_unwind
   1: core::panicking::panic_fmt
   2: rowan::cursor::SyntaxNode::covering_element
   3: ide::inlay_hints::inlay_hints
   4: std::panicking::try
   5: rust_analyzer::handlers::handle_inlay_hints
   6: std::panicking::try
   7: <F as threadpool::FnBox>::call_box
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
stack backtrace:
   0: _rust_begin_unwind
   1: core::panicking::panic_fmt
[Error - 1:38:58 PM] Request textDocument/inlayHint failed.
  Message: request handler panicked: Bad range: node range 0..39, range 0..52
  Code: -32603 
   2: rowan::cursor::SyntaxNode::token_at_offset
   3: ide_ssr::from_comment::ssr_from_comment
   4: ide::ssr::ssr_assists
   5: std::panicking::try
   6: ide::Analysis::assists_with_fixes
   7: rust_analyzer::handlers::handle_code_action
   8: std::panicking::try
   9: <F as threadpool::FnBox>::call_box
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
stack backtrace:
   0: _rust_begin_unwind
   1: core::panicking::panic_fmt
   2: rowan::cursor::SyntaxNode::token_at_offset
   3: ide_ssr::from_comment::ssr_from_comment
   4: ide::ssr::ssr_assists
   5: std::panicking::try
   6: ide::Analysis::assists_with_fixes
   7: rust_analyzer::handlers::handle_code_action
   8: std::panicking::try
   9: <F as threadpool::FnBox>::call_box
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
[Error - 1:40:14 PM] Request textDocument/inlayHint failed.
  Message: Invalid offset
  Code: -32603 

I see messages like "expected a name", "expected arguments", "expected a block" in the error. If it helps, line 751 in the cursor.rs file (https://github.com/rust-analyzer/rowan/blob/master/src/cursor.rs) is the assertion within this code:

pub fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset<SyntaxToken> {
        // TODO: this could be faster if we first drill-down to node, and only
        // then switch to token search. We should also replace explicit
        // recursion with a loop.
        let range = self.text_range();
        assert!(
            range.start() <= offset && offset <= range.end(),
            "Bad offset: range {:?} offset {:?}",
            range,
            offset
        );
        if range.is_empty() {
            return TokenAtOffset::None;
        }

=== REDACTED FOR BREVITY ===

I don't know where to take it from here.

@flodiebold
Copy link
Member

Ok, so apparently you don't get any completions at all? This is indeed a separate issue then. Some things to check when you report a new issue would be:

  • does pressing Ctrl+Space do anything? even if rust-analyzer isn't working, you'd expect VSCode's text suggestions to show up unless they're disabled.
  • do you have quick suggestions enabled in the VSCode settings?
  • do any other completions work? e.g. if you type let x = 1; x. and press Ctrl+Space?

@tgmerritt
Copy link

Son of a b#@$%

image

Forgive me, for I have sinned.

Changed the value, everything started working...

Thank you.

@roybarman
Copy link

roybarman commented Jul 20, 2022

Son of a b#@$%

image

Forgive me, for I have sinned.

Changed the value, everything started working...

Thank you.

Thank you! This worked, so you are forgiven for your sin ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-completion autocompletion A-lsp LSP conformance issues and missing features C-bug Category: bug E-unknown It's unclear if the issue is E-hard or E-easy without digging in
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants