Skip to content

diagnostics: point to coroutine body on higher-ranked auto trait errors#156226

Open
shivendra02467 wants to merge 1 commit into
rust-lang:mainfrom
shivendra02467:fix-diagnostic-155880
Open

diagnostics: point to coroutine body on higher-ranked auto trait errors#156226
shivendra02467 wants to merge 1 commit into
rust-lang:mainfrom
shivendra02467:fix-diagnostic-155880

Conversation

@shivendra02467

@shivendra02467 shivendra02467 commented May 6, 2026

Copy link
Copy Markdown
Contributor

Fixes #155880

When encountering a higher-ranked auto trait bound error involving a coroutine or async function,the trait solver previously used the span of the outermost cause (eg. spawn(...) or is_send(...)).

This PR modifies the TraitPlaceholderMismatch formatting logic to walk down the ObligationCauseCode chain.If the obligation originates from a ty::Coroutine or ty::CoroutineWitness, it extracts that specific span, providing a much more accurate underline for the user.

Before:

error: implementation of `Send` is not general enough
  --> src/main.rs:25:5
   |
25 |     is_send(outer())
   |     ^^^^^^^^^^^^^^^^ implementation of `Send` is not general enough

After:

error: implementation of `Send` is not general enough
  --> src/main.rs:13:74
   |
13 |   async fn inner<'a, T: Trait + 'a>(_: T, x: T::Assoc<'a>) -> T::Assoc<'a> {
   |  __________________________________________________________________________^
14 | |     std::future::ready(x).await
15 | | }
   | |_^ implementation of `Send` is not general enough

@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 May 6, 2026
@rustbot

rustbot commented May 6, 2026

Copy link
Copy Markdown
Collaborator

r? @nnethercote

rustbot has assigned @nnethercote.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 73 candidates
  • Random selection from 20 candidates

@nnethercote

Copy link
Copy Markdown
Contributor

Seems plausible but I don't know enough about the underlying issue to review effectively. Let's try someone else:

r? @lcnr

@rustbot rustbot assigned lcnr and unassigned nnethercote May 8, 2026
@shivendra02467

Copy link
Copy Markdown
Contributor Author

Hi @lcnr, just a gentle ping on this whenever you have a moment! Since you opened the original issue, I'd love to get your thoughts on this approach.

Comment on lines +242 to +261

loop {
match current_code {
ObligationCauseCode::MatchImpl(inner_cause, _) => {
current_code = inner_cause.code();
}
ObligationCauseCode::BuiltinDerived(derived) => {
let self_ty = derived.parent_trait_pred.skip_binder().self_ty();

if let ty::Coroutine(def_id, _) | ty::CoroutineWitness(def_id, _) =
self_ty.kind()
{
span = self.tcx().def_span(*def_id);
break;
}

current_code = &derived.parent_code;
}
_ => break,
}

@lcnr lcnr Jun 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

it's good to see that this information is already accessible. We should also keep the original span, we want to know "where do we require things to be Send and error" and "why do we error".

So instead of replacing the span, it would be good to add an additional note, so sth like

error: implementation of `Send` is not general enough
  --> src/main.rs:25:5
   |
25 |     is_send(outer())
   |     ^^^^^^^^^^^^^^^^ implementation of `Send` is not general enough
  --> src/main.rs:13:74
   |
13 |   async fn inner<'a, T: Trait + 'a>(_: T, x: T::Assoc<'a>) -> T::Assoc<'a> {
   |  __________________________________________________________________________^
14 | |     std::future::ready(x).await
15 | | }
   | |_^ this async block has a field of type `&'0 u32` which is not known to be `Send` 
   = note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
   = note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Makes total sense, I'll get that updated. also
In your example, you mention extracting the specific interior field type (&'0 u32). Dynamically extracting the exact interior type that caused the failure from the placeholder error seems like a much larger/more complex change.
Would a generic note like "this coroutine or async block is not general enough" be acceptable for the scope of this PR, or were you hoping to get the specific interior type extraction implemented here as well?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

"this async block captures a value whose type is not Send" or sth?

an async block being not general enough doesn't really make sense to me. But ye, having some more general "this async block needs to impl Send seems fine. I think you can get the type of the affected field by looking at the self type of its child obligation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't know how we talk about the fields of coroutine witnesses in diagnostics, cc @rust-lang/wg-diagnostics or maybe @rust-lang/lang-docs

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

updated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

you can compute this def_id at the end of the error here? No longer have to do it at the start of the function

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

that makes total sense, i've updated the PR, thanks!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

"this async block captures a value whose type is not Send" or sth?

Sounds right to me.

@lcnr lcnr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

gj finding the relevant information here and sorry for not getting to this earlier, I've been quite busy due to RustWeek

View changes since this review

@shivendra02467

Copy link
Copy Markdown
Contributor Author

gj finding the relevant information here and sorry for not getting to this earlier, I've been quite busy due to RustWeek

Thanks! and no problem.

@shivendra02467 shivendra02467 force-pushed the fix-diagnostic-155880 branch from 8c5f8d8 to d561ece Compare June 11, 2026 16:17
@rustbot

This comment has been minimized.

@shivendra02467 shivendra02467 force-pushed the fix-diagnostic-155880 branch from d561ece to ba78256 Compare June 11, 2026 16:33
@rustbot

rustbot commented Jun 11, 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.

| __________________________________________________________________________-
LL | | std::future::ready(x).await
LL | | }
| |_- this async fn captures a value with an unsatisfied trait bound

@lcnr lcnr Jun 12, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

cc @rust-lang/types I don't know how to best word this annotation. Thoughts?

I feel like "captures a value" is not completely ideal

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'll hold off on changing the "captures a value..." text until the types team weighs in on what terminology they prefer here!

@shivendra02467 shivendra02467 force-pushed the fix-diagnostic-155880 branch from ba78256 to 0606c3e Compare June 12, 2026 12:39
@shivendra02467 shivendra02467 force-pushed the fix-diagnostic-155880 branch from 0606c3e to 6789fc0 Compare June 12, 2026 18:38
@shivendra02467

Copy link
Copy Markdown
Contributor Author

Awesome, thanks for confirming that phrasing, @traviscross!

@lcnr I've pushed an update that makes the label dynamically match the phrasing traviscross approved. It now grabs the specific trait name, so it will output "this async fn captures a value whose type is not Send" (or whichever trait is failing).

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.

coroutine higher-ranked auto trait errors should point at the definition whose bound vars are part of the error

5 participants