-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Do not consider async task_context
to be alive across yields
#105668
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting solution to this problem. Left a few ideas for ways to harden it, because I'm worried about subtle bugs...
// If this is the `&mut Context<'_>` async resume argument, or we are | ||
// just visiting a `_task_context = yield ()` expression from async | ||
// lowering, we do *not* consider this type to be live across yields. | ||
if Some(hir_id) == self.task_context_hid || self.in_await_yield { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to more strongly assert that the thing that we're intentionally not considering live across the yield is a &mut Context<'_>
? Maybe assert on the value of ty: Ty<'tcx>
above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do I best assert that though without manually constructing a matching type? I could probably get the expected resume_ty from the generator somehow and use that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't you destructure the type, check if it's a reference to a specific ADT? The Context type is a lang item, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, did that now, though its a bit more complicated than hoped.
Did also rename some things and added more comments.
// If this is the `&mut Context<'_>` async resume argument, or we are | ||
// just visiting a `_task_context = yield ()` expression from async | ||
// lowering, we do *not* consider this type to be live across yields. | ||
if Some(hir_id) == self.task_context_hid || self.in_await_yield { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain why we need both of these checks? Shouldn't we always be accessing this context type through the same local variable? Could you drop in_await_yield
and maybe match on expr
instead?
I'm thinking that it should be a ExprKind::Path
or something... you could see that it resolved to the argument we're expecting it to be.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried matching just on the ExprKind::Path
of the lhs of the assignment. The problem is also the yield
itself, more specifically the ()
going into it, and the &mut Context<'_>
coming out of it.
Fun fact, by skipping the whole expression, it also avoids putting a ()
into the generator witness in some cases.
1251ec1
to
c8b1bb1
Compare
This does not fix #105501. |
c8b1bb1
to
a653e28
Compare
When lowering async constructs to generators, the resume argument is guaranteed not to be alive across yield points. However the simple `generator_interior` analysis thinks it is. Because of that, the resume ty was part of the `GeneratorWitness` and considered to be part of the generator type, even though it is not really. This prevented async blocks from being `UnwindSafe`, and possibly `Send` in some cases. The code now special cases the fact that the `task_context` of async blocks is never alive across yield points.
a653e28
to
34faed0
Compare
Given #105915 reverting the PR that regressed the root issue, not sure if we want to land this as-is. |
☔ The latest upstream changes (presumably #105918) made this pull request unmergeable. Please resolve the merge conflicts. |
That revert PR probably broke cg_clif again. It is fine for the beta branch, but something like this PR + reverting the revert is necessary for cg_clif. |
I do have an idea for cg_clif. Since it is mostly concerned with the MIR after the generators have been properly transformed, which happens after type checking, it should be possible to:
|
That would work I think. |
Going to close this for now, I will open a separate PR with just the testcase that is good to have. |
When lowering async constructs to generators, the resume argument is guaranteed not to be alive across yield points. However the simple
generator_interior
analysis thinks it is. Because of that, the resume ty was part of theGeneratorWitness
and considered to be part of the generator type, even though it is not really.This prevented async blocks from being
UnwindSafe
, and possiblySend
in some cases.The code now special cases the fact that the
task_context
of async blocks is never alive across yield points.This fixes one regression from #105250.
r? @compiler-errors