Skip to content

Suggest turbofish for multi-param generics used as call arguments - #160104

Open
martonmoro wants to merge 1 commit into
rust-lang:mainfrom
martonmoro:fix-missing-turbofish-diagnostic
Open

Suggest turbofish for multi-param generics used as call arguments#160104
martonmoro wants to merge 1 commit into
rust-lang:mainfrom
martonmoro:fix-missing-turbofish-diagnostic

Conversation

@martonmoro

@martonmoro martonmoro commented Jul 28, 2026

Copy link
Copy Markdown

Fixes #159745

When parsing bar(Many<i32, Many<(), i32, S, S>, i32, i32>::new()) the parser reads < as
Binary(Lt) and the comma as the end of argument 1. At > it tries to parse a RHS and finds a bare
comma, hence expected expression, found ',', and the rest of the "arguments" are parsed wrong.

parse_expr_paren_seq now parses the list once, noting each argument that came out as Binary(Lt).
If a later argument fails to parse, it walks those candidates nearest-first and checks whether the
rest is generic args followed by :: or (. If none prove out, the parser is restored to where it died and the original
error is returned untouched.

@rustbot

rustbot commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

The parser was modified, potentially altering the grammar of (stable) Rust
which would be a breaking change.

cc @fmease

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jul 28, 2026
@rustbot

rustbot commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the pull request, and welcome! The Rust Project is excited to review your changes, and you should hear from @hanna-kruppe (or someone else) some time within the next two weeks.

Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (S-waiting-on-review and S-waiting-on-author) stays updated, invoking these commands when appropriate:

  • @rustbot author: the review is finished, PR author should check the comments and take action accordingly
  • @rustbot review: the author is ready for a review, this PR will be queued again in the reviewer's queue
Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler, parser
  • compiler, parser expanded to 74 candidates
  • Random selection from 18 candidates

@hanna-kruppe

Copy link
Copy Markdown
Contributor

I’m not familiar enough with the parser code to review this, and won’t have time to get familiar with it, so: @rustbot reroll

@rustbot rustbot assigned chenyukang and unassigned hanna-kruppe Aug 2, 2026
@@ -0,0 +1,24 @@
struct Many<A, B, C, D> {

@chenyukang chenyukang Aug 7, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

can we use run-rustfix for this test?

View changes since the review

Comment thread compiler/rustc_parse/src/parser/expr.rs Outdated
let failed = self.create_snapshot_for_diagnostic();
self.restore_snapshot(start);
match self.parse_paren_comma_seq(|p| {
let expr = p.parse_expr_catch_underscore(Restrictions::empty())?;

@chenyukang chenyukang Aug 7, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The fallback here reparses the entire argument list and applies recovery to every Binary(Lt). If a later argument causes the initial parse failure, earlier valid comparisons are reconsidered.

For example this code:

struct S;
struct Many<A, B, C, D>(A, B, C, D);

impl<A, B, C, D> Many<A, B, C, D> {
    fn new() -> Self {
        todo!()
    }
}

fn take_three(_: bool, _: bool, _: Many<i32, Many<(), i32, S, S>, i32, i32>) {}

fn main() {
    let (a, b, c, d) = (1, 2, 3, 4);
    take_three(a < b, c > (d), Many<i32, Many<(), i32, S, S>, i32, i32>::new());
}

the current output is:

  --> /tmp/now.rs:14:16
   |
14 |     take_three(a < b, c > (d), Many<i32, Many<(), i32, S, S>, i32, i32>::new());
   |                ^^^^^
   |
help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
   |
14 |     take_three(a ::< b, c > (d), Many<i32, Many<(), i32, S, S>, i32, i32>::new());
   |                  ++

error: generic args in this position require the turbofish syntax
  --> /tmp/now.rs:14:32
   |
14 |     take_three(a < b, c > (d), Many<i32, Many<(), i32, S, S>, i32, i32>::new());
   |                                ^^^^^^^^
   |
help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
   |
14 |     take_three(a < b, c > (d), Many::<i32, Many<(), i32, S, S>, i32, i32>::new());
   |                                    ++

error[E0061]: this function takes 3 arguments but 2 arguments were supplied
  --> /tmp/now.rs:14:5
   |
14 |     take_three(a < b, c > (d), Many<i32, Many<(), i32, S, S>, i32, i32>::new());
   |     ^^^^^^^^^^----------------------------------------------------------------- argument #3 of type `Many<i32, Many<(), i32, S, S>, i32, i32>` is missing
   |
note: function defined here
  --> /tmp/now.rs:10:4
   |
10 | fn take_three(_: bool, _: bool, _: Many<i32, Many<(), i32, S, S>, i32, i32>) {}
   |    ^^^^^^^^^^                   -------------------------------------------
help: provide the argument
   |
14 |     take_three(a < b, c > (d), Many<i32, Many<(), i32, S, S>, i32, i32>::new(), /* Many<i32, Many<(), i32, S, S>, i32, i32> */);
   |                                                                               ++++++++++++++++++++++++++++++++++++++++++++++++

which is wrong.

The nightly output for this code is :

error: expected expression, found `,`
  --> src/main.rs:14:61
   |
14 |     take_three(a < b, c > (d), Many<i32, Many<(), i32, S, S>, i32, i32>::new());
   |                                                             ^ expected expression

which points out the rootcause.

View changes since the review

Comment thread compiler/rustc_parse/src/parser/expr.rs Outdated
// The attempt above can emit diagnostics before it fails (like in
// `tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs`), and parsing again the same
// tokens would emit them a second time.
if self.dcx().err_count() != err_count {

@chenyukang chenyukang Aug 7, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

seems like a hack here.

View changes since the review

Comment thread compiler/rustc_parse/src/parser/expr.rs Outdated
let failed = self.create_snapshot_for_diagnostic();
self.restore_snapshot(start);
match self.parse_paren_comma_seq(|p| {
let expr = p.parse_expr_catch_underscore(Restrictions::empty())?;

@chenyukang chenyukang Aug 7, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

generally, i don't like the way of repeat the same parsing here, can we do in the way of stop where error happened and try to speculatively detect a missing turbofish.

View changes since the review

@rust-bors

This comment has been minimized.

@martonmoro
martonmoro force-pushed the fix-missing-turbofish-diagnostic branch from ae1ac48 to e0bdad9 Compare August 13, 2026 10:01
@rustbot

rustbot commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@martonmoro

Copy link
Copy Markdown
Author

@chenyukang, thank you for the review! I reworked it, and now the whole argument list retry is gone. Now it records candidate <s and checks them (nearest first) only after a real parse failure.

@martonmoro
martonmoro requested a review from chenyukang August 13, 2026 11:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Missing turbofish in nested type params has terse diagnostic

4 participants