Skip to content

Revert "Remove the witness type from coroutine args" #145193

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

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/rustc_borrowck/src/type_check/input_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// them with fresh ty vars.
resume_ty: next_ty_var(),
yield_ty: next_ty_var(),
witness: next_ty_var(),
},
)
.args,
Expand Down
12 changes: 9 additions & 3 deletions compiler/rustc_hir_analysis/src/collect/generics_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,14 +339,20 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
// for info on the usage of each of these fields.
let dummy_args = match kind {
ClosureKind::Closure => &["<closure_kind>", "<closure_signature>", "<upvars>"][..],
ClosureKind::Coroutine(_) => {
&["<coroutine_kind>", "<resume_ty>", "<yield_ty>", "<return_ty>", "<upvars>"][..]
}
ClosureKind::Coroutine(_) => &[
"<coroutine_kind>",
"<resume_ty>",
"<yield_ty>",
"<return_ty>",
"<witness>",
"<upvars>",
][..],
ClosureKind::CoroutineClosure(_) => &[
"<closure_kind>",
"<closure_signature_parts>",
"<upvars>",
"<bound_captures_by_ref>",
"<witness>",
][..],
};

Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_hir_typeck/src/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Resume type defaults to `()` if the coroutine has no argument.
let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit);

let interior = Ty::new_coroutine_witness(tcx, expr_def_id.to_def_id(), parent_args);

// Coroutines that come from coroutine closures have not yet determined
// their kind ty, so make a fresh infer var which will be constrained
// later during upvar analysis. Regular coroutines always have the kind
Expand All @@ -180,6 +182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
resume_ty,
yield_ty,
return_ty: liberated_sig.output(),
witness: interior,
tupled_upvars_ty,
},
);
Expand Down Expand Up @@ -207,6 +210,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
// Compute all of the variables that will be used to populate the coroutine.
let resume_ty = self.next_ty_var(expr_span);
let interior = self.next_ty_var(expr_span);

let closure_kind_ty = match expected_kind {
Some(kind) => Ty::from_closure_kind(tcx, kind),
Expand Down Expand Up @@ -239,6 +243,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
),
tupled_upvars_ty,
coroutine_captures_by_ref_ty,
coroutine_witness_ty: interior,
},
);

Expand Down
29 changes: 19 additions & 10 deletions compiler/rustc_middle/src/ty/generic_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,29 +96,38 @@ impl<'tcx> rustc_type_ir::inherent::GenericArgs<TyCtxt<'tcx>> for ty::GenericArg
signature_parts_ty,
tupled_upvars_ty,
coroutine_captures_by_ref_ty,
coroutine_witness_ty,
] => ty::CoroutineClosureArgsParts {
parent_args,
closure_kind_ty: closure_kind_ty.expect_ty(),
signature_parts_ty: signature_parts_ty.expect_ty(),
tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
coroutine_captures_by_ref_ty: coroutine_captures_by_ref_ty.expect_ty(),
coroutine_witness_ty: coroutine_witness_ty.expect_ty(),
},
_ => bug!("closure args missing synthetics"),
}
}

fn split_coroutine_args(self) -> ty::CoroutineArgsParts<TyCtxt<'tcx>> {
match self[..] {
[ref parent_args @ .., kind_ty, resume_ty, yield_ty, return_ty, tupled_upvars_ty] => {
ty::CoroutineArgsParts {
parent_args,
kind_ty: kind_ty.expect_ty(),
resume_ty: resume_ty.expect_ty(),
yield_ty: yield_ty.expect_ty(),
return_ty: return_ty.expect_ty(),
tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
}
}
[
ref parent_args @ ..,
kind_ty,
resume_ty,
yield_ty,
return_ty,
witness,
tupled_upvars_ty,
] => ty::CoroutineArgsParts {
parent_args,
kind_ty: kind_ty.expect_ty(),
resume_ty: resume_ty.expect_ty(),
yield_ty: yield_ty.expect_ty(),
return_ty: return_ty.expect_ty(),
witness: witness.expect_ty(),
tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
},
_ => bug!("coroutine args missing synthetics"),
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,9 @@ where
Ok(ty::Binder::dummy(vec![args.as_coroutine_closure().tupled_upvars_ty()]))
}

ty::Coroutine(def_id, args) => {
ty::Coroutine(_, args) => {
let coroutine_args = args.as_coroutine();
Ok(ty::Binder::dummy(vec![
coroutine_args.tupled_upvars_ty(),
Ty::new_coroutine_witness(
ecx.cx(),
def_id,
ecx.cx().mk_args(coroutine_args.parent_args().as_slice()),
),
]))
Ok(ty::Binder::dummy(vec![coroutine_args.tupled_upvars_ty(), coroutine_args.witness()]))
}

ty::CoroutineWitness(def_id, args) => Ok(ecx
Expand Down Expand Up @@ -252,14 +245,7 @@ where
Movability::Movable => {
if ecx.cx().features().coroutine_clone() {
let coroutine = args.as_coroutine();
Ok(ty::Binder::dummy(vec![
coroutine.tupled_upvars_ty(),
Ty::new_coroutine_witness(
ecx.cx(),
def_id,
ecx.cx().mk_args(coroutine.parent_args().as_slice()),
),
]))
Ok(ty::Binder::dummy(vec![coroutine.tupled_upvars_ty(), coroutine.witness()]))
} else {
Err(NoSolution)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1166,7 +1166,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if self.tcx().features().coroutine_clone() {
let resolved_upvars =
self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
if resolved_upvars.is_ty_var() {
let resolved_witness =
self.infcx.shallow_resolve(args.as_coroutine().witness());
if resolved_upvars.is_ty_var() || resolved_witness.is_ty_var() {
// Not yet resolved.
candidates.ambiguous = true;
} else {
Expand Down
14 changes: 3 additions & 11 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2196,11 +2196,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
args.as_coroutine()
.upvar_tys()
.iter()
.chain([Ty::new_coroutine_witness(
self.tcx(),
coroutine_def_id,
self.tcx().mk_args(args.as_coroutine().parent_args()),
)])
.chain([args.as_coroutine().witness()])
.collect::<Vec<_>>(),
)
} else {
Expand Down Expand Up @@ -2331,13 +2327,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
ty::Binder::dummy(AutoImplConstituents { types: vec![ty], assumptions: vec![] })
}

ty::Coroutine(def_id, args) => {
ty::Coroutine(_, args) => {
let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
let witness = Ty::new_coroutine_witness(
self.tcx(),
def_id,
self.tcx().mk_args(args.as_coroutine().parent_args()),
);
let witness = args.as_coroutine().witness();
ty::Binder::dummy(AutoImplConstituents {
types: [ty].into_iter().chain(iter::once(witness)).collect(),
assumptions: vec![],
Expand Down
27 changes: 27 additions & 0 deletions compiler/rustc_type_ir/src/ty_kind/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ use crate::{self as ty, Interner};
/// `yield` inside the coroutine.
/// * `GR`: The "return type", which is the type of value returned upon
/// completion of the coroutine.
/// * `GW`: The "coroutine witness".
#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
pub struct ClosureArgs<I: Interner> {
Expand Down Expand Up @@ -238,6 +239,8 @@ pub struct CoroutineClosureArgsParts<I: Interner> {
/// while the `tupled_upvars_ty`, representing the by-move version of the same
/// captures, will be `(String,)`.
pub coroutine_captures_by_ref_ty: I::Ty,
/// Witness type returned by the generator produced by this coroutine-closure.
pub coroutine_witness_ty: I::Ty,
}

impl<I: Interner> CoroutineClosureArgs<I> {
Expand All @@ -248,6 +251,7 @@ impl<I: Interner> CoroutineClosureArgs<I> {
parts.signature_parts_ty.into(),
parts.tupled_upvars_ty.into(),
parts.coroutine_captures_by_ref_ty.into(),
parts.coroutine_witness_ty.into(),
])),
}
}
Expand Down Expand Up @@ -288,6 +292,7 @@ impl<I: Interner> CoroutineClosureArgs<I> {
}

pub fn coroutine_closure_sig(self) -> ty::Binder<I, CoroutineClosureSignature<I>> {
let interior = self.coroutine_witness_ty();
let ty::FnPtr(sig_tys, hdr) = self.signature_parts_ty().kind() else { panic!() };
sig_tys.map_bound(|sig_tys| {
let [resume_ty, tupled_inputs_ty] = *sig_tys.inputs().as_slice() else {
Expand All @@ -297,6 +302,7 @@ impl<I: Interner> CoroutineClosureArgs<I> {
panic!()
};
CoroutineClosureSignature {
interior,
tupled_inputs_ty,
resume_ty,
yield_ty,
Expand All @@ -312,6 +318,10 @@ impl<I: Interner> CoroutineClosureArgs<I> {
self.split().coroutine_captures_by_ref_ty
}

pub fn coroutine_witness_ty(self) -> I::Ty {
self.split().coroutine_witness_ty
}

pub fn has_self_borrows(&self) -> bool {
match self.coroutine_captures_by_ref_ty().kind() {
ty::FnPtr(sig_tys, _) => sig_tys
Expand Down Expand Up @@ -351,6 +361,7 @@ impl<I: Interner> TypeVisitor<I> for HasRegionsBoundAt {
#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
pub struct CoroutineClosureSignature<I: Interner> {
pub interior: I::Ty,
pub tupled_inputs_ty: I::Ty,
pub resume_ty: I::Ty,
pub yield_ty: I::Ty,
Expand Down Expand Up @@ -396,6 +407,7 @@ impl<I: Interner> CoroutineClosureSignature<I> {
resume_ty: self.resume_ty,
yield_ty: self.yield_ty,
return_ty: self.return_ty,
witness: self.interior,
tupled_upvars_ty,
},
);
Expand Down Expand Up @@ -575,6 +587,11 @@ pub struct CoroutineArgsParts<I: Interner> {
pub yield_ty: I::Ty,
pub return_ty: I::Ty,

/// The interior type of the coroutine.
/// Represents all types that are stored in locals
/// in the coroutine's body.
pub witness: I::Ty,

/// The upvars captured by the closure. Remains an inference variable
/// until the upvar analysis, which happens late in HIR typeck.
pub tupled_upvars_ty: I::Ty,
Expand All @@ -590,6 +607,7 @@ impl<I: Interner> CoroutineArgs<I> {
parts.resume_ty.into(),
parts.yield_ty.into(),
parts.return_ty.into(),
parts.witness.into(),
parts.tupled_upvars_ty.into(),
])),
}
Expand All @@ -611,6 +629,15 @@ impl<I: Interner> CoroutineArgs<I> {
self.split().kind_ty
}

/// This describes the types that can be contained in a coroutine.
/// It will be a type variable initially and unified in the last stages of typeck of a body.
/// It contains a tuple of all the types that could end up on a coroutine frame.
/// The state transformation MIR pass may only produce layouts which mention types
/// in this tuple. Upvars are not counted here.
pub fn witness(self) -> I::Ty {
self.split().witness
}

/// Returns an iterator over the list of types of captured paths by the coroutine.
/// In case there was a type error in figuring out the types of the captured path, an
/// empty iterator is returned.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
std::future::ResumeTy,
(),
(),
CoroutineWitness(
DefId(0:5 ~ async_await[ccf8]::a::{closure#0}),
[],
),
(),
],
),
Expand All @@ -26,6 +30,10 @@
std::future::ResumeTy,
(),
(),
CoroutineWitness(
DefId(0:5 ~ async_await[ccf8]::a::{closure#0}),
[],
),
(),
],
),
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/async-await/async-closures/def-path.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ LL | let x = async || {};
| -- the expected `async` closure body
LL |
LL | let () = x();
| ^^ --- this expression has type `{static main::{closure#0}::{closure#0}<?15t> upvar_tys=?14t resume_ty=ResumeTy yield_ty=() return_ty=()}`
| ^^ --- this expression has type `{static main::{closure#0}::{closure#0}<?16t> upvar_tys=?15t resume_ty=ResumeTy yield_ty=() return_ty=() witness={main::{closure#0}::{closure#0}}}`
| |
| expected `async` closure body, found `()`
|
= note: expected `async` closure body `{static main::{closure#0}::{closure#0}<?15t> upvar_tys=?14t resume_ty=ResumeTy yield_ty=() return_ty=()}`
= note: expected `async` closure body `{static main::{closure#0}::{closure#0}<?16t> upvar_tys=?15t resume_ty=ResumeTy yield_ty=() return_ty=() witness={main::{closure#0}::{closure#0}}}`
found unit type `()`

error: aborting due to 1 previous error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,30 @@ LL | Box::new(async { new(|| async { f().await }).await })
= help: consider pinning your async block and casting it to a trait object
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: aborting due to 2 previous errors
error[E0308]: mismatched types
--> $DIR/higher-ranked-auto-trait-6.rs:16:5
|
LL | Box::new(async { new(|| async { f().await }).await })
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}`
found `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}`
= note: no two async blocks, even if identical, have the same type
= help: consider pinning your async block and casting it to a trait object
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0308]: mismatched types
--> $DIR/higher-ranked-auto-trait-6.rs:16:5
|
LL | Box::new(async { new(|| async { f().await }).await })
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}`
found `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}`
= note: no two async blocks, even if identical, have the same type
= help: consider pinning your async block and casting it to a trait object
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0308`.
14 changes: 14 additions & 0 deletions tests/ui/async-await/recursive-async-auto-trait-overflow.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Regression test for <https://github.com/rust-lang/rust/issues/145151>.

//@ edition: 2024
//@ check-pass

async fn process<'a>() {
Box::pin(process()).await;
}

fn require_send(_: impl Send) {}

fn main() {
require_send(process());
}
Copy link
Contributor

Choose a reason for hiding this comment

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

why did this error?

We've got

  • coroutine<'a>: Send
  • requires witness<'a>: Send
  • requires Box<Pin<coroutine<'!0>>: Send?
  • requires coroutine<'!0>: Send
  • requires witness<'!0>: Send
  • requires Box<Pin<coroutine<'!1>>: Send?
  • ....

But with this revert we get

  • coroutine<'a, witness<'a>>: Send
  • requires witness<'a>: Send
  • requires Box<Pin<coroutine<'!0, witness<'!1>>>>: Send?
  • requires coroutine<'!0, witness<'!1>>: Send
  • requires witness<'!1>: Send
  • requires Box<Pin<coroutine<'!2, witness<'!3>>>>: Send?
  • ....

Copy link
Contributor

Choose a reason for hiding this comment

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

ah, see #145194

4 changes: 2 additions & 2 deletions tests/ui/coroutine/print/coroutine-print-verbose-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ LL | | drop(a);
LL | | });
| |______^ coroutine is not `Sync`
|
= help: within `{main::{closure#0} upvar_tys=() resume_ty=() yield_ty=() return_ty=()}`, the trait `Sync` is not implemented for `NotSync`
= help: within `{main::{closure#0} upvar_tys=() resume_ty=() yield_ty=() return_ty=() witness={main::{closure#0}}}`, the trait `Sync` is not implemented for `NotSync`
note: coroutine is not `Sync` as this value is used across a yield
--> $DIR/coroutine-print-verbose-2.rs:20:9
|
Expand All @@ -34,7 +34,7 @@ LL | | drop(a);
LL | | });
| |______^ coroutine is not `Send`
|
= help: within `{main::{closure#1} upvar_tys=() resume_ty=() yield_ty=() return_ty=()}`, the trait `Send` is not implemented for `NotSend`
= help: within `{main::{closure#1} upvar_tys=() resume_ty=() yield_ty=() return_ty=() witness={main::{closure#1}}}`, the trait `Send` is not implemented for `NotSend`
note: coroutine is not `Send` as this value is used across a yield
--> $DIR/coroutine-print-verbose-2.rs:27:9
|
Expand Down
Loading
Loading