Skip to content

Point turbofish inference errors at the uninferred generic arg#153795

Merged
rust-bors[bot] merged 2 commits intorust-lang:mainfrom
arferreira:turbofish-span-improvement
Mar 18, 2026
Merged

Point turbofish inference errors at the uninferred generic arg#153795
rust-bors[bot] merged 2 commits intorust-lang:mainfrom
arferreira:turbofish-span-improvement

Conversation

@arferreira
Copy link
Contributor

@arferreira arferreira commented Mar 12, 2026

Follow-up to #153751.

When a method call has a turbofish with an uninferred generic argument, point the diagnostic span at the specific _ that couldn't be inferred instead of the method name.

Before:

LL |     S.f::<u32, _>(42);
   |       ^ cannot infer type of the type parameter `B`

After:

LL |     S.f::<u32, _>(42);
   |                ^ cannot infer type of the type parameter `B`

Path expressions (None::<_>, foo::<_>()) are not handled yet, that's a separate code path.

cc @eggyal

@rustbot
Copy link
Collaborator

rustbot commented Mar 12, 2026

Some changes occurred in need_type_info.rs

cc @lcnr

@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 Mar 12, 2026
@rustbot

This comment was marked as resolved.

@rust-log-analyzer

This comment has been minimized.

@arferreira arferreira force-pushed the turbofish-span-improvement branch from 3051885 to d1648a1 Compare March 12, 2026 21:48
@rust-log-analyzer

This comment has been minimized.

@arferreira arferreira force-pushed the turbofish-span-improvement branch from d1648a1 to b2573ab Compare March 12, 2026 22:39
@eggyal
Copy link
Contributor

eggyal commented Mar 12, 2026

What happens if there are multiple uninferred parameters? 🤔

@arferreira
Copy link
Contributor Author

It points at the first uninferred one. Compiler stops after the first inference failure, so the second gets flagged on the next compile.

Copy link
Contributor

@eggyal eggyal left a comment

Choose a reason for hiding this comment

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

Minor nit, but otherwise LGTM.

View changes since this review

generics.has_own_self() as usize + generics.own_counts().lifetimes,
)
&& let Some(arg) =
hir_args.args.iter().filter(|a| a.is_ty_or_const()).nth(idx)
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor nit, which saves on performing the is_ty_or_const check on each parameter.

Suggested change
hir_args.args.iter().filter(|a| a.is_ty_or_const()).nth(idx)
hir_args.args.get(hir_args.num_lifetime_params() + idx)

Even more minor, if one were to move the adjustment of argument_index from lines 1268-1270 to after this statement ends on 1290, it wouldn't need to be reversed in the checked_sub above.

Copy link
Member

@Kivooeo Kivooeo left a comment

Choose a reason for hiding this comment

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

should be possible to use if let guards here, not sure if you found this more prettier or not, this up to you

View changes since this review

Comment on lines 1274 to 1290
let span = match expr.kind {
ExprKind::MethodCall(path, ..) => path.ident.span,
ExprKind::MethodCall(segment, ..) => {
if have_turbofish
&& let Some(hir_args) = segment.args
&& let Some(idx) = argument_index.checked_sub(
generics.has_own_self() as usize + generics.own_counts().lifetimes,
)
&& let Some(arg) =
hir_args.args.iter().filter(|a| a.is_ty_or_const()).nth(idx)
{
arg.span()
} else {
segment.ident.span
}
}
_ => expr.span,
};
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
let span = match expr.kind {
ExprKind::MethodCall(path, ..) => path.ident.span,
ExprKind::MethodCall(segment, ..) => {
if have_turbofish
&& let Some(hir_args) = segment.args
&& let Some(idx) = argument_index.checked_sub(
generics.has_own_self() as usize + generics.own_counts().lifetimes,
)
&& let Some(arg) =
hir_args.args.iter().filter(|a| a.is_ty_or_const()).nth(idx)
{
arg.span()
} else {
segment.ident.span
}
}
_ => expr.span,
};
let span = match expr.kind {
ExprKind::MethodCall(segment, ..)
if have_turbofish
&& let Some(hir_args) = segment.args
&& let Some(idx) = argument_index.checked_sub(
generics.has_own_self() as usize + generics.own_counts().lifetimes,
)
&& let Some(arg) = hir_args.args.iter().filter(|a| a.is_ty_or_const()).nth(idx) =>
{
arg.span()
}
ExprKind::MethodCall(segment, ..) => segment.ident.span,
_ => expr.span,
};

Copy link
Contributor

Choose a reason for hiding this comment

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

isn't it better do do a find here/maybe even enumerate().find(..)

Copy link
Contributor

Choose a reason for hiding this comment

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

if you don't use the actual argument, but still refer to all generic_args, then using position seems fine. enumerate.find() and then only using the index should just be worse than position.

I expected that being able to easily name the unconstrained arg would be helpful. If it is not, keeping position here is fine

@arferreira arferreira force-pushed the turbofish-span-improvement branch from b2573ab to e485708 Compare March 13, 2026 11:29
@eggyal
Copy link
Contributor

eggyal commented Mar 16, 2026

This PR doesn't have an assigned reviewer. @Kivooeo or @lcnr, since you've already taken a look are either of you happy to take the assignment or should we ask rustbot to pick someone?

@Kivooeo
Copy link
Member

Kivooeo commented Mar 16, 2026

I'll likely take a look tomorrow

r? me

@Kivooeo
Copy link
Member

Kivooeo commented Mar 17, 2026

cool, thanks

@bors r=Kivooeo,eggyal rollup

@rust-bors
Copy link
Contributor

rust-bors bot commented Mar 17, 2026

📌 Commit b258fe1 has been approved by Kivooeo,eggyal

It is now in the queue for this repository.

⚠️ The following reviewer(s) could not be found: eggyal

@rust-bors rust-bors bot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 17, 2026
rust-bors bot pushed a commit that referenced this pull request Mar 17, 2026
…uwer

Rollup of 6 pull requests

Successful merges:

 - #152998 (std: make `OsString::truncate` a no-op when `len > current_len`)
 - #153682 (Tweak E0599 note)
 - #153795 (Point turbofish inference errors at the uninferred generic arg)
 - #153994 (move `tests/ui/invalid` tests to new folders)
 - #154006 (attrs: Ignore ExprKind::Err when converting path attr expr to lit)
 - #154012 (unstable impl of `From<{i64, u64}> for f128`)
@rust-bors rust-bors bot merged commit 6f13b52 into rust-lang:main Mar 18, 2026
11 checks passed
@rustbot rustbot added this to the 1.96.0 milestone Mar 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. 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.

6 participants