Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ fn build_union_fields_for_direct_tag_coroutine<'ll, 'tcx>(
common_upvar_names,
);

let span = coroutine_layout.variant_source_info[variant_index].span;
let span = coroutine_layout.variant_source_info()[variant_index].span;
let source_info = if !span.is_dummy() {
let loc = cx.lookup_debug_loc(span.lo());
Some((file_metadata(cx, &loc.file), loc.line as c_uint))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
use rustc_codegen_ssa::traits::MiscCodegenMethods;
use rustc_hir::def::CtorKind;
use rustc_index::IndexSlice;
use rustc_middle::mir::CoroutineLayout;
use rustc_middle::mir::QueriedCoroutineLayout;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty, VariantDef};
use rustc_span::{Span, Symbol, bug};
Expand Down Expand Up @@ -292,7 +292,7 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
variant_index: VariantIdx,
coroutine_type_and_layout: TyAndLayout<'tcx>,
coroutine_type_di_node: &'ll DIType,
coroutine_layout: &CoroutineLayout<'tcx>,
coroutine_layout: QueriedCoroutineLayout<'tcx>,
common_upvar_names: &IndexSlice<FieldIdx, Symbol>,
) -> &'ll DIType {
let variant_name = CoroutineArgs::variant_name(variant_index);
Expand Down Expand Up @@ -325,10 +325,10 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
// Fields that just belong to this variant/state
let state_specific_fields: SmallVec<_> = (0..variant_layout.fields.count())
.map(|field_index| {
let coroutine_saved_local = coroutine_layout.variant_fields[variant_index]
let coroutine_saved_local = coroutine_layout.variant_fields()[variant_index]
[FieldIdx::from_usize(field_index)];
let field_name_maybe =
coroutine_layout.field_tys[coroutine_saved_local].debuginfo_name;
coroutine_layout.field_tys()[coroutine_saved_local].debuginfo_name;
let field_name = field_name_maybe
.as_ref()
.map(|s| Cow::from(s.as_str()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
// with enums?
let variant_name = format!("{}", variant_index.as_usize()).into();

let span = coroutine_layout.variant_source_info[variant_index].span;
let span = coroutine_layout.variant_source_info()[variant_index].span;
let source_info = if !span.is_dummy() {
let loc = cx.lookup_debug_loc(span.lo());
Some((file_metadata(cx, &loc.file), loc.line))
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2300,7 +2300,8 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, opaque_def_id: LocalDefId) -> ErrorG
&& let Some(coroutine_layout) = tcx.mir_coroutine_witnesses(closure_def_id)
{
for interior_ty in &coroutine_layout.field_tys {
label_match(interior_ty.ty, interior_ty.source_info.span);
let ty = interior_ty.ty.instantiate_identity().skip_norm_wip();
label_match(ty, interior_ty.source_info.span);
}
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/mir/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,7 @@ fn write_coroutine_layout<'tcx>(
field_tys.iter_enumerated()
{
let ignore_for_traits = if *ignore_for_traits { " (ignored for traits)" } else { "" };
let ty = ty.instantiate_identity().skip_norm_wip();
let indented_body = format!("{INDENT}{INDENT}field {field:?}: {ty}{ignore_for_traits};",);
if options.include_extra_comments {
writeln!(w, "{0:ALIGN$} // in {1}", indented_body, comment(tcx, *source_info))?;
Expand Down
60 changes: 58 additions & 2 deletions compiler/rustc_middle/src/mir/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use rustc_macros::{StableHash, TyDecodable, TyEncodable, TypeFoldable, TypeVisit
use rustc_span::{Span, Symbol};

use super::{ConstValue, SourceInfo};
use crate::ty::{self, CoroutineArgsExt, Ty};
use crate::ty::{self, CoroutineArgsExt, EarlyBinder, GenericArgsRef, Ty, TyCtxt, Unnormalized};

rustc_index::newtype_index! {
#[stable_hash]
Expand All @@ -22,7 +22,9 @@ rustc_index::newtype_index! {
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(TyEncodable, TyDecodable, StableHash, TypeFoldable, TypeVisitable)]
pub struct CoroutineSavedTy<'tcx> {
pub ty: Ty<'tcx>,
#[type_foldable(identity)]
#[type_visitable(ignore)]
Comment on lines +25 to +26

@lcnr lcnr Sep 22, 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.

oh, why is this TypeFoldable?

ignoring this field is wrong. We should not type fold CoroutineSavedTy. What breaks if you remove the derive there?

View changes since the review

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

if I just remove the derive I get an error about how CoroutineLayout can't implement TypeFoldable because its fields don't implement it.

full error
error[E0277]: the trait bound `mir::query::CoroutineSavedTy<'_>: rustc_type_ir::TypeFoldable<context::TyCtxt<'_>>` is not satisfied
  --> compiler/rustc_middle/src/mir/query.rs:39:5
   |
37 |   #[derive(TyEncodable, TyDecodable, StableHash, TypeFoldable, TypeVisitable)]
   |                                                  ------------
   |                                                  |
   |                                                  required by a bound introduced by this call
   |                                                  in this derive macro expansion
38 |   pub struct CoroutineLayout<'tcx> {
39 |       /// The type of every local stored inside the coroutine.
   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
   |
  ::: /home/levy/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/synstructure-0.13.2/src/macros.rs:95:9
   |
95 | /         pub fn $derives(
96 | |             i: $crate::macros::TokenStream
97 | |         ) -> $crate::macros::TokenStream {
   | |________________________________________- in this expansion of `#[derive(TypeFoldable)]`
   |
help: the trait `rustc_type_ir::TypeFoldable<context::TyCtxt<'_>>` is not implemented for `mir::query::CoroutineSavedTy<'_>`
  --> compiler/rustc_middle/src/mir/query.rs:24:1
   |
24 | pub struct CoroutineSavedTy<'tcx> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = help: the following other types implement trait `rustc_type_ir::TypeFoldable<I>`:
             `&'tcx list::RawList<(), (rustc_type_ir::OpaqueTypeKey<context::TyCtxt<'tcx>>, ty::Ty<'tcx>)>` implements `rustc_type_ir::TypeFoldable<context::TyCtxt<'tcx>>`
             `&'tcx list::RawList<(), generic_args::GenericArg<'tcx>>` implements `rustc_type_ir::TypeFoldable<context::TyCtxt<'tcx>>`
             `&'tcx list::RawList<(), rustc_span::def_id::LocalDefId>` implements `rustc_type_ir::TypeFoldable<context::TyCtxt<'tcx>>`
             `&RawList<(), Binder<TyCtxt<'tcx>, ExistentialPredicate<TyCtxt<'tcx>>>>` implements `rustc_type_ir::TypeFoldable<context::TyCtxt<'tcx>>`
             `&RawList<(), OutlivesClause<TyCtxt<'tcx>, GenericArg<'tcx>>>` implements `rustc_type_ir::TypeFoldable<context::TyCtxt<'tcx>>`
             `&'tcx list::RawList<(), syntax::ProjectionElem<mir::Local, ty::Ty<'tcx>>>` implements `rustc_type_ir::TypeFoldable<context::TyCtxt<'tcx>>`
             `&'tcx list::RawList<(), ty::Ty<'tcx>>` implements `rustc_type_ir::TypeFoldable<context::TyCtxt<'tcx>>`
             `&'tcx list::RawList<(), ty::consts::Const<'tcx>>` implements `rustc_type_ir::TypeFoldable<context::TyCtxt<'tcx>>`
           and 262 others
   = note: required for `rustc_index::IndexVec<mir::query::CoroutineSavedLocal, mir::query::CoroutineSavedTy<'_>>` to implement `rustc_type_ir::TypeFoldable<context::TyCtxt<'_>>`
   = note: the full name for the type has been written to '/home/levy/src/rust-lang/rust/build-rust-analyzer/x86_64-unknown-linux-gnu/stage1-rustc/x86_64-unknown-linux-gnu/release/build/rustc_middle/374f18fe06c7bef2/out/rustc_middle-374f18fe06c7bef2.long-type-8635111359931186326.txt'
   = note: consider using `--verbose` to print the full type name to the console

If I add a #[type_foldable(identity)] for the field_tys field which stores the CoroutineSavedTys then x check and x test tests/ui both succeed

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.

why does CoroutineLAyout implement TypeFoldable :>

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

the chain goes like this:

CoroutineSavedTy -> CoroutineLayout -> CoroutineInfo -> Body

and if I remove it from Body I get an error at rustc_public_bridge/src/builder.rs about how Body needs to be TypeFoldable because EarlyBinder::bind requires that as a trait bound

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.

hmm, that's kind of scuffed. Body shouldn't be TypeFoldable ideally as some of the fields of MIR bodies don't make sense after it. Fixing that is annoying and non-trivial and ignoring the EArlyBinder here is fine. Coolio

pub ty: EarlyBinder<'tcx, Ty<'tcx>>,
/// Source info corresponding to the local in the original MIR body.
pub source_info: SourceInfo,
/// Whether the local should be ignored for trait bound computations.
Expand Down Expand Up @@ -81,6 +83,60 @@ impl Debug for CoroutineLayout<'_> {
}
}

/// The result of the `coroutine_layout` function.
///
/// Wraps a regular `CoroutineLayout` with its arguments, providing accessors
/// that instantiate the stored `Ty` if necessary.
#[derive(Debug, Copy, Clone)]
pub struct QueriedCoroutineLayout<'tcx> {
layout: &'tcx CoroutineLayout<'tcx>,
args: Option<GenericArgsRef<'tcx>>,

@levyry levyry Oct 1, 2026 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I made this an Option like you wrote previously, I assume this is so that when this is None we know to use fn instantiate_identity, but during my refactorings I didn't really see any places that would warrant instantiating this field with None. Could you let me know if I misinterpreted your comment or if I didn't instantiate this field correctly somewhere?

View changes since the review

}

impl<'tcx> QueriedCoroutineLayout<'tcx> {
pub fn new(layout: &'tcx CoroutineLayout<'tcx>, args: Option<GenericArgsRef<'tcx>>) -> Self {
Self { layout, args }
}

pub fn get_ty(
&self,
tcx: TyCtxt<'tcx>,
field: CoroutineSavedLocal,
) -> Unnormalized<'tcx, Ty<'tcx>> {
if let Some(args) = self.args {
self.layout.field_tys[field].ty.instantiate(tcx, args)
} else {
self.layout.field_tys[field].ty.instantiate_identity()
}
}

pub fn get_identity_ty(&self, field: CoroutineSavedLocal) -> Unnormalized<'tcx, Ty<'tcx>> {
self.layout.field_tys[field].ty.instantiate_identity()
}

pub fn field_tys(&self) -> &'tcx IndexVec<CoroutineSavedLocal, CoroutineSavedTy<'tcx>> {
&self.layout.field_tys
}

pub fn variant_fields(
&self,
) -> &'tcx IndexVec<VariantIdx, IndexVec<FieldIdx, CoroutineSavedLocal>> {
&self.layout.variant_fields
}

pub fn variant_source_info(&self) -> &'tcx IndexVec<VariantIdx, SourceInfo> {
&self.layout.variant_source_info
}

pub fn storage_conflicts(&self) -> &'tcx BitMatrix<CoroutineSavedLocal, CoroutineSavedLocal> {
&self.layout.storage_conflicts
}

pub fn raw_layout(self) -> &'tcx CoroutineLayout<'tcx> {
self.layout
}
}

/// The result of the `mir_const_qualif` query.
///
/// Each field (except `tainted_by_errors`) corresponds to an implementer of the `Qualif` trait in
Expand Down
21 changes: 15 additions & 6 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@ pub use self::typeck_results::{
UserTypeKind,
};
use crate::diagnostics::{OpaqueHiddenTypeMismatch, TypeMismatchReason};
use crate::mir::{Body, CoroutineLayout, CoroutineSavedLocal, MirPhase, SourceInfo};
use crate::mir::{
Body, CoroutineLayout, CoroutineSavedLocal, MirPhase, QueriedCoroutineLayout, SourceInfo,
};
use crate::query::{IntoQueryKey, Providers};
use crate::ty;
use crate::ty::codec::{TyDecoder, TyEncoder};
Expand Down Expand Up @@ -1942,13 +1944,15 @@ impl<'tcx> TyCtxt<'tcx> {
self,
def_id: DefId,
args: GenericArgsRef<'tcx>,
) -> Result<&'tcx CoroutineLayout<'tcx>, &'tcx LayoutError<'tcx>> {
) -> Result<QueriedCoroutineLayout<'tcx>, &'tcx LayoutError<'tcx>> {
let coroutine_kind_ty = args.as_coroutine().kind_ty();
let mir = self.optimized_mir(def_id);
let ty = || Ty::new_coroutine(self, def_id, args);
// Regular coroutine
if coroutine_kind_ty.is_unit() {
mir.coroutine_layout_raw().ok_or_else(|| self.layout_error(LayoutError::Unknown(ty())))
mir.coroutine_layout_raw()
.map(|layout| QueriedCoroutineLayout::new(layout, Some(args)))
.ok_or_else(|| self.layout_error(LayoutError::Unknown(ty())))
} else {
// If we have a `Coroutine` that comes from an coroutine-closure,
// then it may be a by-move or by-ref body.
Expand All @@ -1962,6 +1966,7 @@ impl<'tcx> TyCtxt<'tcx> {
// a by-ref coroutine.
if identity_kind_ty == coroutine_kind_ty {
mir.coroutine_layout_raw()
.map(|layout| QueriedCoroutineLayout::new(layout, Some(args)))
.ok_or_else(|| self.layout_error(LayoutError::Unknown(ty())))
} else {
assert_matches!(coroutine_kind_ty.to_opt_closure_kind(), Some(ClosureKind::FnOnce));
Expand All @@ -1971,6 +1976,7 @@ impl<'tcx> TyCtxt<'tcx> {
);
self.optimized_mir(self.coroutine_by_move_body_def_id(def_id))
.coroutine_layout_raw()
.map(|layout| QueriedCoroutineLayout::new(layout, Some(args)))
.ok_or_else(|| self.layout_error(LayoutError::Unknown(ty())))
}
}
Expand All @@ -1983,14 +1989,15 @@ impl<'tcx> TyCtxt<'tcx> {
self,
def_id: DefId,
args: GenericArgsRef<'tcx>,
) -> Result<&'tcx CoroutineLayout<'tcx>, &'tcx LayoutError<'tcx>> {
) -> Result<QueriedCoroutineLayout<'tcx>, &'tcx LayoutError<'tcx>> {
let ty = || Ty::new_coroutine(self, def_id, args);
if args[0].has_placeholders() || args[0].has_non_region_param() {
return Err(self.layout_error(LayoutError::TooGeneric(ty())));
}
let instance = ShimKind::AsyncDropGlue(def_id, Ty::new_coroutine(self, def_id, args));
self.mir_shims(instance)
.coroutine_layout_raw()
.map(|layout| QueriedCoroutineLayout::new(layout, Some(args)))
.ok_or_else(|| self.layout_error(LayoutError::Unknown(ty())))
}

Expand All @@ -2000,7 +2007,7 @@ impl<'tcx> TyCtxt<'tcx> {
self,
def_id: DefId,
args: GenericArgsRef<'tcx>,
) -> Result<&'tcx CoroutineLayout<'tcx>, &'tcx LayoutError<'tcx>> {
) -> Result<QueriedCoroutineLayout<'tcx>, &'tcx LayoutError<'tcx>> {
if self.is_async_drop_in_place_coroutine(def_id) {
// layout of `async_drop_in_place<T>::{closure}` in case,
// when T is a coroutine, contains this internal coroutine's ptr in upvars
Expand All @@ -2021,7 +2028,9 @@ impl<'tcx> TyCtxt<'tcx> {
variant_source_info,
storage_conflicts: BitMatrix::new(0, 0),
};
return Ok(self.arena.alloc(proxy_layout));
let layout = self.arena.alloc(proxy_layout);
let queried_layout = QueriedCoroutineLayout::new(layout, Some(args));
return Ok(queried_layout);
} else {
self.async_drop_coroutine_layout(def_id, args)
}
Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ impl<'tcx> ty::CoroutineArgs<TyCtxt<'tcx>> {
#[inline]
fn variant_range(&self, def_id: DefId, tcx: TyCtxt<'tcx>) -> Range<VariantIdx> {
// FIXME requires optimized MIR
FIRST_VARIANT..tcx.coroutine_layout(def_id, self.args).unwrap().variant_fields.next_index()
FIRST_VARIANT
..tcx.coroutine_layout(def_id, self.args).unwrap().variant_fields().next_index()
}

/// The discriminant for the given variant. Panics if the `variant_index` is
Expand Down Expand Up @@ -162,14 +163,13 @@ impl<'tcx> ty::CoroutineArgs<TyCtxt<'tcx>> {
tcx: TyCtxt<'tcx>,
) -> impl Iterator<Item: Iterator<Item = Ty<'tcx>>> {
let layout = tcx.coroutine_layout(def_id, self.args).unwrap();
layout.variant_fields.iter().map(move |variant| {
layout.variant_fields().iter().map(move |variant| {
variant.iter().map(move |field| {
if tcx.is_async_drop_in_place_coroutine(def_id) {
layout.field_tys[*field].ty
// FIXME(async_drop): this needs a comment for why its correct
layout.get_identity_ty(*field).skip_norm_wip()

@levyry levyry Oct 1, 2026 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This function is only used once here, and I am not sure if it's really needed or not, as ideally get_ty would handle the identity initialization as well, but for this first version of QueriedCoroutineLayout I wanted to include a more personalized API, which I can revise later ^^

View changes since the review

} else {
ty::EarlyBinder::bind(tcx, layout.field_tys[*field].ty)
.instantiate(tcx, self.args)
.skip_norm_wip()
layout.get_ty(tcx, *field).skip_norm_wip()
}
})
})
Expand Down
25 changes: 17 additions & 8 deletions compiler/rustc_mir_transform/src/coroutine/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ use rustc_infer::traits::TraitErrors;
use rustc_lint_defs::builtin::MUST_NOT_SUSPEND;
use rustc_middle::mir::*;
use rustc_middle::ty::consts::ConstExt;
use rustc_middle::ty::{self, CoroutineArgs, CoroutineArgsExt, Ty, TyCtxt, TypingMode};
use rustc_middle::ty::{
self, CoroutineArgs, CoroutineArgsExt, EarlyBinder, Ty, TyCtxt, TypingMode,
};
use rustc_mir_dataflow::impls::{
MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
always_storage_live_locals,
Expand Down Expand Up @@ -341,8 +343,9 @@ impl StorageConflictVisitor<'_> {
}
}

#[tracing::instrument(level = "trace", skip(liveness, body))]
#[tracing::instrument(level = "trace", skip(tcx, liveness, body))]
pub(super) fn compute_layout<'tcx>(
tcx: TyCtxt<'tcx>,
liveness: LivenessInfo,
body: &Body<'tcx>,
) -> (
Expand Down Expand Up @@ -383,7 +386,7 @@ pub(super) fn compute_layout<'tcx>(
};

CoroutineSavedTy {
ty: decl.ty,
ty: EarlyBinder::bind(tcx, decl.ty),
source_info: decl.source_info,
ignore_for_traits,
// Will be set later when walking debuginfo.
Expand Down Expand Up @@ -426,7 +429,11 @@ pub(super) fn compute_layout<'tcx>(
// just use the first one here. That's fine; fields do not move
// around inside coroutines, so it doesn't matter which variant
// index we access them by.
remap[reverse_local_map[saved_local]] = Some((tys[saved_local].ty, variant_index, idx));
remap[reverse_local_map[saved_local]] = Some((
tys[saved_local].ty.instantiate_identity().skip_norm_wip(),
variant_index,
idx,
));
}
variant_source_info.push(source_info_at_suspension_point);
}
Expand Down Expand Up @@ -479,7 +486,7 @@ pub(crate) fn mir_coroutine_witnesses<'tcx>(
// Extract locals which are live across suspension point into `layout`
// `remap` gives a mapping from local indices onto coroutine struct indices
// `storage_liveness` tells us which locals have live storage at suspension points
let (_, coroutine_layout, _) = compute_layout(liveness_info, body);
let (_, coroutine_layout, _) = compute_layout(tcx, liveness_info, body);

check_suspend_tys(tcx, &coroutine_layout, body);
check_field_tys_sized(tcx, &coroutine_layout, def_id);
Expand Down Expand Up @@ -514,7 +521,7 @@ fn check_field_tys_sized<'tcx>(
ObligationCauseCode::SizedCoroutineInterior(def_id),
),
param_env,
field_ty.ty,
field_ty.ty.instantiate_identity().skip_norm_wip(),
tcx.require_lang_item(LangItem::Sized, field_ty.source_info.span),
);
}
Expand All @@ -537,14 +544,16 @@ fn check_suspend_tys<'tcx>(tcx: TyCtxt<'tcx>, layout: &CoroutineLayout<'tcx>, bo
let decl = &layout.field_tys[local];
debug!(?decl);

if !decl.ignore_for_traits && linted_tys.insert(decl.ty) {
let ty = decl.ty.instantiate_identity().skip_norm_wip();

if !decl.ignore_for_traits && linted_tys.insert(ty) {
let Some(hir_id) = decl.source_info.scope.lint_root(&body.source_scopes) else {
continue;
};

check_must_not_suspend_ty(
tcx,
decl.ty,
ty,
hir_id,
SuspendCheckData {
source_span: decl.source_info.span,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/coroutine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1119,7 +1119,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
// Extract locals which are live across suspension point into `layout`
// `remap` gives a mapping from local indices onto coroutine struct indices
// `storage_liveness` tells us which locals have live storage at suspension points
let (remap, layout, storage_liveness) = compute_layout(liveness_info, body);
let (remap, layout, storage_liveness) = compute_layout(tcx, liveness_info, body);

let can_return = can_return(tcx, body, body.typing_env(tcx));

Expand Down
18 changes: 11 additions & 7 deletions compiler/rustc_mir_transform/src/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -766,9 +766,12 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
// since we may be in the process of computing this MIR in the
// first place.
let layout = if def_id == self.caller_body.source.def_id() {
self.caller_body
.coroutine_layout_raw()
.or_else(|| self.tcx.coroutine_layout(def_id, args).ok())
self.caller_body.coroutine_layout_raw().or_else(|| {
self.tcx
.coroutine_layout(def_id, args)
.ok()
.map(|queried| queried.raw_layout())

@levyry levyry Oct 1, 2026 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

raw_layout is only used here in validate.rs. I could remove this fn rewrite this branch to use QueriedCoroutineLayout if you'd like, but it seemed messier to me

View changes since the review

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

To clarify the messiness: in this branch we have a &'a CoroutineLayout instead of a &'tcx CoroutineLayout, so it seems to me the only way to work with QueriedCoroutineLayout directly here is to do:

pub struct QueriedCoroutineLayout<'a, 'tcx> {
    layout: &'a CoroutineLayout<'tcx>,
    args: Option<GenericArgsRef<'tcx>>,
}

which seemed undesirable to me.

})
} else if self.tcx.needs_coroutine_by_move_body_def_id(def_id)
&& let ty::ClosureKind::FnOnce =
args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap()
Expand All @@ -778,7 +781,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
// Same if this is the by-move body of a coroutine-closure.
self.caller_body.coroutine_layout_raw()
} else {
self.tcx.coroutine_layout(def_id, args).ok()
self.tcx
.coroutine_layout(def_id, args)
.ok()
.map(|queried| queried.raw_layout())
};

let Some(layout) = layout else {
Expand All @@ -802,9 +808,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
return;
};

ty::EarlyBinder::bind(self.tcx, f_ty.ty)
.instantiate(self.tcx, args)
.skip_norm_wip()
f_ty.ty.instantiate(self.tcx, args).skip_norm_wip()
} else if let Some(&f_ty) = args.as_coroutine().upvar_tys().get(f.index()) {
f_ty
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3494,7 +3494,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
for &local in variant {
let decl = &coroutine_info.field_tys[local];
debug!(?decl);
if ty_matches(ty::Binder::dummy(decl.ty)) && !decl.ignore_for_traits {
let ty = decl.ty.instantiate_identity().skip_norm_wip();
if ty_matches(ty::Binder::dummy(ty)) && !decl.ignore_for_traits {
interior_or_upvar_span = Some(CoroutineInteriorOrUpvar::Interior(
decl.source_info.span,
Some((source_info.span, from_awaited_ty)),
Expand Down
Loading
Loading