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

Erroneous right paren when annotating closure with tuple return type #16084

Open
Lunderberg opened this issue Dec 11, 2023 · 6 comments
Open
Labels
A-ide general IDE features C-bug Category: bug

Comments

@Lunderberg
Copy link

Reproduction Steps

  1. Create a new project with cargo new temp.
  2. In bin.rs, define the following function:
fn func() {
    let closure = |a: i64| {
        let b = 2 * a;
        (a, b)
    };
}
  1. Place the cursor after |a: i64|, just before the opening {.
  2. Type -> (i64, i64)

Expected behavior
After adding the return type annotation to the closure, the editor should have the following text:

fn func() {
    let closure = |a: i64| -> (i64, i64) {
        let b = 2 * a;
        (a, b)
    };
}

Observed behavior
After adding the return type annotation to the closure, the editor has the following text.

fn func() {
    let closure = |a: i64| -> (i64, i64) {
        let b = 2 * a;
        (a, b)
    });
}

The extra closing ) occurs at the end of the closure definition, causing a compilation error due to unmatched parentheses. Because the insertion of the extra ) may be several lines away from the point where the user is typing, this is difficult to spot as it occurs.

Suspected Mechanism

  1. The opening ( in (i64, i64) triggers the on_char_typed, which then delegates to on_opening_bracket_typed
  2. on_opening_bracket_typed calls bracket_expr, to determine if the ( occurred just prior to an expression that should be parenthesized.
  3. bracket_expr recognizes the body of the lambda as a block expression, and inserts a closing ) between the closing } of the lambda and the ;

rust-analyzer version:

  • First noticed in rust-analyzer 1.74.1 (a28077b 2023-12-04)
  • Last nightly build without the error: rust-analyzer 1.74.0-nightly (203c57d 2023-09-17)
  • First nightly build with the error: rust-analyzer 1.74.0-nightly (65ea825 2023-09-18)

The list of rustc commits, starting at the first known bad commit is here. The subtree updates for rust-analyzer in this window are from this PR. This PR included commit 0f1cde70, which was an upstreaming of the rust-analyzer PR #15532, and seems the most likely commit to have introduced this error.

rustc version: rustc 1.74.1 (a28077b28 2023-12-04)

relevant settings: (eg. client settings, or environment variables like CARGO, RUSTC, RUSTUP_HOME or CARGO_HOME)

  • emacs version 27.1
  • rust-mode version 20230805.1558 (latest version on melpa)
  • lsp-mode version 20231124.833 (~1 week away from latest version on melpa)
@Lunderberg Lunderberg added the C-bug Category: bug label Dec 11, 2023
@rdxdkr
Copy link

rdxdkr commented Dec 11, 2023

I've noticed the same issue even in a much simpler case.

Given the following:
let a = 1 + 2 % 3;

I want to surround the first two operands in parentheses like this:
let a = (1 + 2) % 3;

but when adding a '(' to the left of 1, a ')' is automatically added to the right of 3:
let a = (1 + 2 % 3);

Is there a way to somehow disable it until it's fixed? In cases such as this one, there's a risk to introduce some sneaky bugs due to operators' precedence rules.

rust-analyzer version: 0.3.1766-standalone (457b966b1 2023-12-10)
rustc version: 1.74.1 (a28077b28 2023-12-04)
VS Code version: 1.85.0 af28b32d7e553898b2a91af498b1fb666fdebe0c x64

@Lunderberg
Copy link
Author

@rdxdkr True, and that has been messing me up as well. That said, in an expression context, the insertion of a closing ) isn't technically incorrect, just very unexpected. When writing this issue, I wanted to limit report the case that had incorrect behavior regardless of preferences

Is there a way to somehow disable it until it's fixed?

If you prevent your editor from sending the textDocument/onTypeFormatting command to the LSP, that should work. From emacs, the only way I've found to do so is to disable all on-type formatting with lsp-toggle-on-type-formatting.

@Lingepumpe
Copy link

Having the same issue using vscode. I did not find any settings to disable these automatic parenthesis being inserted - I can see some people liking this as a feature, but it should definitively be configurable.

@sjackman
Copy link

sjackman commented Jan 14, 2025

tl;dr: Disable automatic insertion of closing parentheses and braces with the configuration "rust-analyzer.typing.excludeChars": "|<({"

This behaviour is quite surprising to me. It was difficult to troubleshoot and figure out what which feature of Rust Analyzer is responsible for it and how to disable it. The incorrect automatically inserted parenthesis or brace can be so far away in the code that it's not visible on the screen. I found the VSCode feature Editor: Auto Closing Brackets and tried disabling it with "editor.autoClosingBrackets": "never" with no luck. Perhaps setting "editor.autoClosingBrackets": "never" could also disable this feature. Additionally the documentation for analyzer.typing.excludeChars could explicitly mention that it is used to disable auto-closing parentheses and braces to make it more discoverable, something like:

Set this parameter to |<({ to disable auto-closing pipes, angle brackets, parentheses, and braces.

This feature is documented at https://rust-analyzer.github.io/manual.html#assists-code-actions under Assists (Code Actions) then add_braces.

Related issue

Related PRs

@Veykril
Copy link
Member

Veykril commented Jan 15, 2025

Yes, we should probably disable it fully by default (and flip the setting around to enable the chars instead). Making this work correctly is super tricky and the current implementation just lacks too many decent heuristics.

@Veykril
Copy link
Member

Veykril commented Jan 15, 2025

#18939 flips the setting to be opt-in and reduces the enabled default to = (insert ; when typing let pat = and . (auto-indent method call chains)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ide general IDE features C-bug Category: bug
Projects
None yet
Development

No branches or pull requests

6 participants