diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index fbed6f33e5928..68b945aec3769 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1388,6 +1388,7 @@ fn opaque_type_cycle_error( struct OpaqueTypeCollector { opaques: Vec<DefId>, closures: Vec<DefId>, + coroutine: Vec<DefId>, } impl<'tcx> ty::visit::TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { @@ -1396,10 +1397,14 @@ fn opaque_type_cycle_error( self.opaques.push(def); ControlFlow::Continue(()) } - ty::Closure(def_id, ..) | ty::Coroutine(def_id, ..) => { + ty::Closure(def_id, ..) => { self.closures.push(def_id); t.super_visit_with(self) } + ty::Coroutine(def_id, ..) => { + self.coroutine.push(def_id); + t.super_visit_with(self) + } _ => t.super_visit_with(self), } } @@ -1417,43 +1422,48 @@ fn opaque_type_cycle_error( err.span_label(sp, format!("returning here with type `{ty}`")); } - for closure_def_id in visitor.closures { - let Some(closure_local_did) = closure_def_id.as_local() else { - continue; - }; - let typeck_results = tcx.typeck(closure_local_did); - - let mut label_match = |ty: Ty<'_>, span| { - for arg in ty.walk() { - if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Alias( - ty::Opaque, - ty::AliasTy { def_id: captured_def_id, .. }, - ) = *ty.kind() - && captured_def_id == opaque_def_id.to_def_id() - { - err.span_label( - span, - format!( - "{} captures itself here", - tcx.def_descr(closure_def_id) - ), - ); - } + let label_match = |err: &mut DiagnosticBuilder<'_, _>, ty: Ty<'_>, span, def_id| { + for arg in ty.walk() { + if let ty::GenericArgKind::Type(ty) = arg.unpack() + && let ty::Alias( + ty::Opaque, + ty::AliasTy { def_id: captured_def_id, .. }, + ) = *ty.kind() + && captured_def_id == opaque_def_id.to_def_id() + { + err.span_label( + span, + format!("{} captures itself here", tcx.def_descr(def_id)), + ); } - }; + } + }; + let capture = |err: &mut DiagnosticBuilder<'_, _>, def_id: DefId| { + let Some(local_id) = def_id.as_local() else { + return; + }; + let typeck_results = tcx.typeck(local_id); // Label any closure upvars that capture the opaque - for capture in typeck_results.closure_min_captures_flattened(closure_local_did) - { - label_match(capture.place.ty(), capture.get_path_span(tcx)); + for capture in typeck_results.closure_min_captures_flattened(local_id) { + label_match(err, capture.place.ty(), capture.get_path_span(tcx), def_id); } - // Label any coroutine locals that capture the opaque - if tcx.is_coroutine(closure_def_id) - && let Some(coroutine_layout) = tcx.mir_coroutine_witnesses(closure_def_id) - { + }; + + for closure_def_id in visitor.closures { + capture(&mut err, closure_def_id); + } + + for coroutine_def_id in visitor.coroutine { + capture(&mut err, coroutine_def_id); + if let Some(coroutine_layout) = tcx.mir_coroutine_witnesses(coroutine_def_id) { for interior_ty in &coroutine_layout.field_tys { - label_match(interior_ty.ty, interior_ty.source_info.span); + label_match( + &mut err, + interior_ty.ty, + interior_ty.source_info.span, + coroutine_def_id, + ); } } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 765bb7a362e5a..3123dc19e2101 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1617,6 +1617,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { for (def_id, encode_const, encode_opt) in keys_and_jobs { debug_assert!(encode_const || encode_opt); + let def_kind = tcx.def_kind(def_id); + debug!("EntryBuilder::encode_mir({:?})", def_id); if encode_opt { record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id)); @@ -1626,7 +1628,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.closure_saved_names_of_captured_variables[def_id.to_def_id()] <- tcx.closure_saved_names_of_captured_variables(def_id)); - if self.tcx.is_coroutine(def_id.to_def_id()) + if DefKind::Closure == def_kind + && tcx.is_coroutine(def_id.to_def_id()) && let Some(witnesses) = tcx.mir_coroutine_witnesses(def_id) { record!(self.tables.mir_coroutine_witnesses[def_id.to_def_id()] <- witnesses); @@ -1653,7 +1656,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } record!(self.tables.promoted_mir[def_id.to_def_id()] <- tcx.promoted_mir(def_id)); - if self.tcx.is_coroutine(def_id.to_def_id()) + if DefKind::Closure == def_kind + && tcx.is_coroutine(def_id.to_def_id()) && let Some(witnesses) = tcx.mir_coroutine_witnesses(def_id) { record!(self.tables.mir_coroutine_witnesses[def_id.to_def_id()] <- witnesses); diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 19b6496b102ef..c8236434f5696 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -638,25 +638,25 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - ); (sig.inputs().to_vec(), sig.output(), None) } - DefKind::Closure if coroutine_kind.is_some() => { - let coroutine_ty = tcx.type_of(def_id).instantiate_identity(); - let ty::Coroutine(_, args, _) = coroutine_ty.kind() else { bug!() }; - let args = args.as_coroutine(); - let yield_ty = args.yield_ty(); - let return_ty = args.return_ty(); - (vec![coroutine_ty, args.resume_ty()], return_ty, Some(yield_ty)) - } DefKind::Closure => { - let closure_ty = tcx.type_of(def_id).instantiate_identity(); - let ty::Closure(_, args) = closure_ty.kind() else { bug!() }; - let args = args.as_closure(); - let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), args.sig()); - let self_ty = match args.kind() { - ty::ClosureKind::Fn => Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, closure_ty), - ty::ClosureKind::FnMut => Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, closure_ty), - ty::ClosureKind::FnOnce => closure_ty, - }; - ([self_ty].into_iter().chain(sig.inputs().to_vec()).collect(), sig.output(), None) + let ty = tcx.type_of(def_id).instantiate_identity(); + if let ty::Coroutine(_, args, _) = ty.kind() { + let args = args.as_coroutine(); + let yield_ty = args.yield_ty(); + let return_ty = args.return_ty(); + (vec![ty, args.resume_ty()], return_ty, Some(yield_ty)) + } else if let ty::Closure(_, args) = ty.kind() { + let args = args.as_closure(); + let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), args.sig()); + let self_ty = match args.kind() { + ty::ClosureKind::Fn => Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty), + ty::ClosureKind::FnMut => Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, ty), + ty::ClosureKind::FnOnce => ty, + }; + ([self_ty].into_iter().chain(sig.inputs().to_vec()).collect(), sig.output(), None) + } else { + bug!() + } } dk => bug!("{:?} is not a body: {:?}", def_id, dk), }; diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 4eba7103c0cda..c046ff7ef7d67 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -37,7 +37,10 @@ pub(crate) fn thir_body( // The resume argument may be missing, in that case we need to provide it here. // It will always be `()` in this case. - if tcx.is_coroutine(owner_def.to_def_id()) && body.params.is_empty() { + if body.params.is_empty() + && tcx.def_kind(owner_def) == DefKind::Closure + && tcx.is_coroutine(owner_def.to_def_id()) + { cx.thir.params.push(Param { ty: Ty::new_unit(tcx), pat: None, @@ -119,45 +122,30 @@ impl<'tcx> Cx<'tcx> { fn closure_env_param(&self, owner_def: LocalDefId, owner_id: HirId) -> Option<Param<'tcx>> { match self.tcx.def_kind(owner_def) { - DefKind::Closure if self.tcx.is_coroutine(owner_def.to_def_id()) => { - let coroutine_ty = self.typeck_results.node_type(owner_id); - let coroutine_param = Param { - ty: coroutine_ty, - pat: None, - ty_span: None, - self_kind: None, - hir_id: None, - }; - Some(coroutine_param) - } DefKind::Closure => { - let closure_ty = self.typeck_results.node_type(owner_id); - - let ty::Closure(closure_def_id, closure_args) = *closure_ty.kind() else { - bug!("closure expr does not have closure type: {:?}", closure_ty); + let ty = self.typeck_results.node_type(owner_id); + let ty = if ty.is_coroutine() { + ty + } else if let ty::Closure(closure_def_id, closure_args) = *ty.kind() { + let bound_vars = self + .tcx + .mk_bound_variable_kinds(&[ty::BoundVariableKind::Region(ty::BrEnv)]); + let br = ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind: ty::BrEnv, + }; + let env_region = ty::Region::new_bound(self.tcx, ty::INNERMOST, br); + let closure_env_ty = + self.tcx.closure_env_ty(closure_def_id, closure_args, env_region).unwrap(); + self.tcx.instantiate_bound_regions_with_erased(ty::Binder::bind_with_vars( + closure_env_ty, + bound_vars, + )) + } else { + bug!("closure expr does not have closure type: {:?}", ty); }; - - let bound_vars = - self.tcx.mk_bound_variable_kinds(&[ty::BoundVariableKind::Region(ty::BrEnv)]); - let br = ty::BoundRegion { - var: ty::BoundVar::from_usize(bound_vars.len() - 1), - kind: ty::BrEnv, - }; - let env_region = ty::Region::new_bound(self.tcx, ty::INNERMOST, br); - let closure_env_ty = - self.tcx.closure_env_ty(closure_def_id, closure_args, env_region).unwrap(); - let liberated_closure_env_ty = self.tcx.instantiate_bound_regions_with_erased( - ty::Binder::bind_with_vars(closure_env_ty, bound_vars), - ); - let env_param = Param { - ty: liberated_closure_env_ty, - pat: None, - ty_span: None, - self_kind: None, - hir_id: None, - }; - - Some(env_param) + let param = Param { ty, pat: None, ty_span: None, self_kind: None, hir_id: None }; + Some(param) } _ => None, } diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 9a16003bdc9ae..d6bb729f976e1 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -84,7 +84,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp { // FIXME(welseywiser) const prop doesn't work on coroutines because of query cycles // computing their layout. - if tcx.is_coroutine(def_id.to_def_id()) { + if def_kind == DefKind::Closure && tcx.is_coroutine(def_id.to_def_id()) { trace!("ConstProp skipped for coroutine {:?}", def_id); return; } diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 99eecb567f277..b441607035055 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -61,7 +61,7 @@ impl<'tcx> MirLint<'tcx> for ConstPropLint { // FIXME(welseywiser) const prop doesn't work on coroutines because of query cycles // computing their layout. - if tcx.is_coroutine(def_id.to_def_id()) { + if def_kind == DefKind::Closure && tcx.is_coroutine(def_id.to_def_id()) { trace!("ConstPropLint skipped for coroutine {:?}", def_id); return; } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index fff760ba399be..f20b500130874 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -395,13 +395,13 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { /// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't /// end up missing the source MIR due to stealing happening. fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> { - if tcx.is_coroutine(def.to_def_id()) { + let def_kind = tcx.def_kind(def); + if def_kind == DefKind::Closure && tcx.is_coroutine(def.to_def_id()) { tcx.ensure_with_value().mir_coroutine_witnesses(def); } let mir_borrowck = tcx.mir_borrowck(def); - let is_fn_like = tcx.def_kind(def).is_fn_like(); - if is_fn_like { + if def_kind.is_fn_like() { // Do not compute the mir call graph without said call graph actually being used. if pm::should_run_pass(tcx, &inline::Inline) { tcx.ensure_with_value().mir_inliner_callees(ty::InstanceDef::Item(def.to_def_id()));