From d35dbbdc8ec3437807213ec103e42659467d9a77 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 22 Jan 2023 14:37:16 +0000 Subject: [PATCH 1/4] Store the body type in THIR. --- compiler/rustc_middle/src/thir.rs | 26 ++++++++++++-- compiler/rustc_mir_build/src/build/mod.rs | 40 +++++---------------- compiler/rustc_mir_build/src/thir/cx/mod.rs | 25 +++++++++++-- tests/ui/thir-print/thir-flat.stdout | 3 ++ 4 files changed, 57 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 6f2dac46753..f9820fdd394 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -20,7 +20,7 @@ use rustc_middle::mir::interpret::AllocId; use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp}; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, AdtDef, Ty, UpvarSubsts}; +use rustc_middle::ty::{self, AdtDef, FnSig, Ty, UpvarSubsts}; use rustc_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation}; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; @@ -33,7 +33,12 @@ pub mod print; pub mod visit; macro_rules! thir_with_elements { - ($($name:ident: $id:ty => $value:ty => $format:literal,)*) => { + ( + $($field_name:ident: $field_ty:ty,)* + + @elements: + $($name:ident: $id:ty => $value:ty => $format:literal,)* + ) => { $( newtype_index! { #[derive(HashStable)] @@ -47,14 +52,20 @@ macro_rules! thir_with_elements { /// This can be indexed directly by any THIR index (e.g. [`ExprId`]). #[derive(Debug, HashStable, Clone)] pub struct Thir<'tcx> { + $( + pub $field_name: $field_ty, + )* $( pub $name: IndexVec<$id, $value>, )* } impl<'tcx> Thir<'tcx> { - pub fn new() -> Thir<'tcx> { + pub fn new($($field_name: $field_ty,)*) -> Thir<'tcx> { Thir { + $( + $field_name, + )* $( $name: IndexVec::new(), )* @@ -76,6 +87,9 @@ macro_rules! thir_with_elements { pub const UPVAR_ENV_PARAM: ParamId = ParamId::from_u32(0); thir_with_elements! { + body_type: BodyTy<'tcx>, + +@elements: arms: ArmId => Arm<'tcx> => "a{}", blocks: BlockId => Block => "b{}", exprs: ExprId => Expr<'tcx> => "e{}", @@ -83,6 +97,12 @@ thir_with_elements! { params: ParamId => Param<'tcx> => "p{}", } +#[derive(Debug, HashStable, Clone)] +pub enum BodyTy<'tcx> { + Const(Ty<'tcx>), + Fn(FnSig<'tcx>), +} + /// Description of a type-checked function parameter. #[derive(Clone, Debug, HashStable)] pub struct Param<'tcx> { diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index a6de8684c0f..9232c931afb 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -47,8 +47,6 @@ pub(crate) fn mir_built( /// Construct the MIR for a given `DefId`. fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_> { - let body_owner_kind = tcx.hir().body_owner_kind(def.did); - // Ensure unsafeck and abstract const building is ran before we steal the THIR. // We can't use `ensure()` for `thir_abstract_const` as it doesn't compute the query // if inputs are green. This can cause ICEs when calling `thir_abstract_const` after @@ -65,16 +63,15 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ } let body = match tcx.thir_body(def) { - Err(error_reported) => construct_error(tcx, def.did, body_owner_kind, error_reported), + Err(error_reported) => construct_error(tcx, def.did, error_reported), Ok((thir, expr)) => { // We ran all queries that depended on THIR at the beginning // of `mir_build`, so now we can steal it let thir = thir.steal(); - if body_owner_kind.is_fn_or_closure() { - construct_fn(tcx, def, &thir, expr) - } else { - construct_const(tcx, def, &thir, expr) + match thir.body_type { + thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, &thir, expr, fn_sig), + thir::BodyTy::Const(ty) => construct_const(tcx, def, &thir, expr, ty), } } }; @@ -434,6 +431,7 @@ fn construct_fn<'tcx>( fn_def: ty::WithOptConstParam, thir: &Thir<'tcx>, expr: ExprId, + fn_sig: ty::FnSig<'tcx>, ) -> Body<'tcx> { let span = tcx.def_span(fn_def.did); let fn_id = tcx.hir().local_def_id_to_hir_id(fn_def.did); @@ -453,11 +451,6 @@ fn construct_fn<'tcx>( .output .span(); - // fetch the fully liberated fn signature (that is, all bound - // types/lifetimes replaced) - let typeck_results = tcx.typeck_opt_const_arg(fn_def); - let fn_sig = typeck_results.liberated_fn_sigs()[fn_id]; - let safety = match fn_sig.unsafety { hir::Unsafety::Normal => Safety::Safe, hir::Unsafety::Unsafe => Safety::FnUnsafe, @@ -563,6 +556,7 @@ fn construct_const<'a, 'tcx>( def: ty::WithOptConstParam, thir: &'a Thir<'tcx>, expr: ExprId, + const_ty: Ty<'tcx>, ) -> Body<'tcx> { let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); @@ -586,20 +580,6 @@ fn construct_const<'a, 'tcx>( _ => span_bug!(tcx.def_span(def.did), "can't build MIR for {:?}", def.did), }; - // Get the revealed type of this const. This is *not* the adjusted - // type of its body, which may be a subtype of this type. For - // example: - // - // fn foo(_: &()) {} - // static X: fn(&'static ()) = foo; - // - // The adjusted type of the body of X is `for<'a> fn(&'a ())` which - // is not the same as the type of X. We need the type of the return - // place to be the type of the constant because NLL typeck will - // equate them. - let typeck_results = tcx.typeck_opt_const_arg(def); - let const_ty = typeck_results.node_type(hir_id); - let infcx = tcx.infer_ctxt().build(); let mut builder = Builder::new( thir, @@ -629,15 +609,11 @@ fn construct_const<'a, 'tcx>( /// /// This is required because we may still want to run MIR passes on an item /// with type errors, but normal MIR construction can't handle that in general. -fn construct_error( - tcx: TyCtxt<'_>, - def: LocalDefId, - body_owner_kind: hir::BodyOwnerKind, - err: ErrorGuaranteed, -) -> Body<'_> { +fn construct_error(tcx: TyCtxt<'_>, def: LocalDefId, err: ErrorGuaranteed) -> Body<'_> { let span = tcx.def_span(def); let hir_id = tcx.hir().local_def_id_to_hir_id(def); let generator_kind = tcx.generator_kind(def); + let body_owner_kind = tcx.hir().body_owner_kind(def); let ty = tcx.ty_error(err); let num_params = match body_owner_kind { diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 20af60a511e..39a68048e26 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -99,9 +99,30 @@ impl<'tcx> Cx<'tcx> { let typeck_results = tcx.typeck_opt_const_arg(def); let did = def.did; let hir = tcx.hir(); + let hir_id = hir.local_def_id_to_hir_id(did); + + let body_type = if hir.body_owner_kind(did).is_fn_or_closure() { + // fetch the fully liberated fn signature (that is, all bound + // types/lifetimes replaced) + BodyTy::Fn(typeck_results.liberated_fn_sigs()[hir_id]) + } else { + // Get the revealed type of this const. This is *not* the adjusted + // type of its body, which may be a subtype of this type. For + // example: + // + // fn foo(_: &()) {} + // static X: fn(&'static ()) = foo; + // + // The adjusted type of the body of X is `for<'a> fn(&'a ())` which + // is not the same as the type of X. We need the type of the return + // place to be the type of the constant because NLL typeck will + // equate them. + BodyTy::Const(typeck_results.node_type(hir_id)) + }; + Cx { tcx, - thir: Thir::new(), + thir: Thir::new(body_type), param_env: tcx.param_env(def.did), region_scope_tree: tcx.region_scope_tree(def.did), typeck_results, @@ -109,7 +130,7 @@ impl<'tcx> Cx<'tcx> { body_owner: did.to_def_id(), adjustment_span: None, apply_adjustments: hir - .attrs(hir.local_def_id_to_hir_id(did)) + .attrs(hir_id) .iter() .all(|attr| attr.name_or_empty() != rustc_span::sym::custom_mir), } diff --git a/tests/ui/thir-print/thir-flat.stdout b/tests/ui/thir-print/thir-flat.stdout index c399fa66b6a..c31e6a218ce 100644 --- a/tests/ui/thir-print/thir-flat.stdout +++ b/tests/ui/thir-print/thir-flat.stdout @@ -1,5 +1,8 @@ DefId(0:3 ~ thir_flat[45a6]::main): Thir { + body_type: Fn( + ([]; c_variadic: false)->(), + ), arms: [], blocks: [ Block { From 7dcc74eee5584639c182aecdfe80a7f5369c5b69 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 25 Oct 2022 17:59:18 +0000 Subject: [PATCH 2/4] Access upvars through a query. --- compiler/rustc_borrowck/src/lib.rs | 10 +- .../src/interpret/validity.rs | 6 +- compiler/rustc_hir_typeck/src/upvar.rs | 3 + compiler/rustc_middle/src/hir/map/mod.rs | 5 + compiler/rustc_middle/src/query/mod.rs | 10 +- compiler/rustc_middle/src/ty/closure.rs | 36 ++--- .../rustc_middle/src/ty/structural_impls.rs | 1 + compiler/rustc_mir_build/src/build/mod.rs | 146 +++++++++--------- compiler/rustc_mir_build/src/thir/cx/expr.rs | 5 +- 9 files changed, 111 insertions(+), 111 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 18d7bde60d7..0f591460e9d 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -202,14 +202,14 @@ fn do_mir_borrowck<'tcx>( let mut errors = error::BorrowckErrors::new(infcx.tcx); // Gather the upvars of a closure, if any. - let tables = tcx.typeck_opt_const_arg(def); - if let Some(e) = tables.tainted_by_errors { + if let Some(e) = input_body.tainted_by_errors { infcx.set_tainted_by_errors(e); errors.set_tainted_by_errors(e); } - let upvars: Vec<_> = tables - .closure_min_captures_flattened(def.did) - .map(|captured_place| { + let upvars: Vec<_> = tcx + .closure_captures(def.did) + .iter() + .map(|&captured_place| { let capture = captured_place.info.capture_kind; let by_ref = match capture { ty::UpvarCapture::ByValue => false, diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index e76d4c1728e..f7881c50960 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -240,10 +240,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // FIXME this should be more descriptive i.e. CapturePlace instead of CapturedVar // https://github.com/rust-lang/project-rfc-2229/issues/46 if let Some(local_def_id) = def_id.as_local() { - let tables = self.ecx.tcx.typeck(local_def_id); - if let Some(captured_place) = - tables.closure_min_captures_flattened(local_def_id).nth(field) - { + let captures = self.ecx.tcx.closure_captures(local_def_id); + if let Some(captured_place) = captures.get(field) { // Sometimes the index is beyond the number of upvars (seen // for a generator). let var_hir_id = captured_place.get_root_variable(); diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index e94915c754e..3e27a78135e 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -526,10 +526,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, base => bug!("Expected upvar, found={:?}", base), }; + let var_ident = self.tcx.hir().ident(var_hir_id); let Some(min_cap_list) = root_var_min_capture_list.get_mut(&var_hir_id) else { let mutability = self.determine_capture_mutability(&typeck_results, &place); let min_cap_list = vec![ty::CapturedPlace { + var_ident, place, info: capture_info, mutability, @@ -628,6 +630,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !ancestor_found { let mutability = self.determine_capture_mutability(&typeck_results, &place); let captured_place = ty::CapturedPlace { + var_ident, place, info: updated_capture_info, mutability, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 2df851a7857..4b5bacac814 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -902,6 +902,11 @@ impl<'hir> Map<'hir> { self.opt_ident(id).map(|ident| ident.span) } + #[inline] + pub fn ident(self, id: HirId) -> Ident { + self.opt_ident(id).unwrap() + } + #[inline] pub fn opt_name(self, id: HirId) -> Option { self.opt_ident(id).map(|ident| ident.name) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 6a34e5ede19..03d2eea7d4a 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -475,14 +475,10 @@ rustc_queries! { } } - query symbols_for_closure_captures( - key: (LocalDefId, LocalDefId) - ) -> &'tcx Vec { - arena_cache + query closure_captures(key: LocalDefId) -> &'tcx [&'tcx ty::CapturedPlace<'tcx>] { desc { - |tcx| "finding symbols for captures of closure `{}` in `{}`", - tcx.def_path_str(key.1.to_def_id()), - tcx.def_path_str(key.0.to_def_id()) + |tcx| "finding symbols for captures of closure `{}`", + tcx.def_path_str(key.to_def_id()) } } diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 6ade8935fc8..65df7204302 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -5,10 +5,11 @@ use crate::{mir, ty}; use std::fmt::Write; -use hir::LangItem; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; -use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::{self as hir, LangItem}; +use rustc_span::symbol::Ident; use rustc_span::{Span, Symbol}; use super::{Ty, TyCtxt}; @@ -129,6 +130,9 @@ impl<'tcx> ClosureKind { #[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)] #[derive(TypeFoldable, TypeVisitable)] pub struct CapturedPlace<'tcx> { + /// Name and span where the binding happens. + pub var_ident: Ident, + /// The `Place` that is captured. pub place: HirPlace<'tcx>, @@ -148,12 +152,8 @@ impl<'tcx> CapturedPlace<'tcx> { } /// Returns a symbol of the captured upvar, which looks like `name__field1__field2`. - fn to_symbol(&self, tcx: TyCtxt<'tcx>) -> Symbol { - let hir_id = match self.place.base { - HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, - base => bug!("Expected an upvar, found {:?}", base), - }; - let mut symbol = tcx.hir().name(hir_id).as_str().to_string(); + pub fn to_symbol(&self) -> Symbol { + let mut symbol = self.var_ident.to_string(); let mut ty = self.place.base_ty; for proj in self.place.projections.iter() { @@ -169,11 +169,7 @@ impl<'tcx> CapturedPlace<'tcx> { .unwrap(); } ty => { - span_bug!( - self.get_capture_kind_span(tcx), - "Unexpected type {:?} for `Field` projection", - ty - ) + bug!("Unexpected type {:?} for `Field` projection", ty) } }, @@ -238,10 +234,14 @@ impl<'tcx> CapturedPlace<'tcx> { } } -fn symbols_for_closure_captures(tcx: TyCtxt<'_>, def_id: (LocalDefId, LocalDefId)) -> Vec { - let typeck_results = tcx.typeck(def_id.0); - let captures = typeck_results.closure_min_captures_flattened(def_id.1); - captures.into_iter().map(|captured_place| captured_place.to_symbol(tcx)).collect() +fn closure_captures<'tcx>( + tcx: TyCtxt<'tcx>, + def: LocalDefId, +) -> &'tcx [&'tcx ty::CapturedPlace<'tcx>] { + let (DefKind::Closure | DefKind::Generator) = tcx.def_kind(def) else { return &[] }; + let typeck_results = tcx.typeck(def); + let captures = typeck_results.closure_min_captures_flattened(def); + tcx.arena.alloc_from_iter(captures) } /// Return true if the `proj_possible_ancestor` represents an ancestor path @@ -434,5 +434,5 @@ impl BorrowKind { } pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { symbols_for_closure_captures, ..*providers } + *providers = ty::query::Providers { closure_captures, ..*providers } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 1d4d76da572..ef643531bb2 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -263,6 +263,7 @@ TrivialTypeTraversalAndLiftImpls! { crate::ty::UniverseIndex, crate::ty::Variance, ::rustc_span::Span, + ::rustc_span::symbol::Ident, ::rustc_errors::ErrorGuaranteed, Field, interpret::Scalar, diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 9232c931afb..b3f9d82829f 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -20,7 +20,7 @@ use rustc_middle::mir::*; use rustc_middle::thir::{ self, BindingMode, Expr, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir, }; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypeckResults}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_span::Symbol; @@ -155,13 +155,13 @@ struct BlockContext(Vec); struct Builder<'a, 'tcx> { tcx: TyCtxt<'tcx>, infcx: InferCtxt<'tcx>, - typeck_results: &'tcx TypeckResults<'tcx>, region_scope_tree: &'tcx region::ScopeTree, param_env: ty::ParamEnv<'tcx>, thir: &'a Thir<'tcx>, cfg: CFG<'tcx>, + def: ty::WithOptConstParam, def_id: DefId, hir_id: hir::HirId, parent_module: DefId, @@ -522,13 +522,7 @@ fn construct_fn<'tcx>( let return_block = unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| { Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { - builder.args_and_body( - START_BLOCK, - fn_def.did, - arguments, - arg_scope, - &thir[expr], - ) + builder.args_and_body(START_BLOCK, arguments, arg_scope, &thir[expr]) })) })); let source_info = builder.source_info(fn_end); @@ -704,9 +698,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { thir, tcx, infcx, - typeck_results: tcx.typeck_opt_const_arg(def), region_scope_tree: tcx.region_scope_tree(def.did), param_env, + def, def_id: def.did.to_def_id(), hir_id, parent_module: tcx.parent_module(hir_id).to_def_id(), @@ -756,14 +750,78 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.var_debug_info, self.fn_span, self.generator_kind, - self.typeck_results.tainted_by_errors, + None, ) } + fn insert_upvar_arg(&mut self) { + let Some(closure_arg) = self.local_decls.get(ty::CAPTURE_STRUCT_LOCAL) else { return }; + + let mut closure_ty = closure_arg.ty; + let mut closure_env_projs = vec![]; + if let ty::Ref(_, ty, _) = closure_ty.kind() { + closure_env_projs.push(ProjectionElem::Deref); + closure_ty = *ty; + } + + let upvar_substs = match closure_ty.kind() { + ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs), + ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs), + _ => return, + }; + + // In analyze_closure() in upvar.rs we gathered a list of upvars used by an + // indexed closure and we stored in a map called closure_min_captures in TypeckResults + // with the closure's DefId. Here, we run through that vec of UpvarIds for + // the given closure and use the necessary information to create upvar + // debuginfo and to fill `self.upvars`. + let capture_tys = upvar_substs.upvar_tys(); + + let tcx = self.tcx; + self.upvars = tcx + .closure_captures(self.def.did) + .iter() + .zip(capture_tys) + .enumerate() + .map(|(i, (captured_place, ty))| { + let name = captured_place.to_symbol(); + + let capture = captured_place.info.capture_kind; + let var_id = match captured_place.place.base { + HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, + _ => bug!("Expected an upvar"), + }; + + let mutability = captured_place.mutability; + + let mut projs = closure_env_projs.clone(); + projs.push(ProjectionElem::Field(Field::new(i), ty)); + match capture { + ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByRef(..) => { + projs.push(ProjectionElem::Deref); + } + }; + + let use_place = Place { + local: ty::CAPTURE_STRUCT_LOCAL, + projection: tcx.mk_place_elems(&projs), + }; + self.var_debug_info.push(VarDebugInfo { + name, + source_info: SourceInfo::outermost(captured_place.var_ident.span), + value: VarDebugInfoContents::Place(use_place), + }); + + let capture = Capture { captured_place, use_place, mutability }; + (var_id, capture) + }) + .collect(); + } + fn args_and_body( &mut self, mut block: BasicBlock, - fn_def_id: LocalDefId, arguments: &IndexVec>, argument_scope: region::Scope, expr: &Expr<'tcx>, @@ -785,69 +843,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - let tcx = self.tcx; - let tcx_hir = tcx.hir(); - let hir_typeck_results = self.typeck_results; - - // In analyze_closure() in upvar.rs we gathered a list of upvars used by an - // indexed closure and we stored in a map called closure_min_captures in TypeckResults - // with the closure's DefId. Here, we run through that vec of UpvarIds for - // the given closure and use the necessary information to create upvar - // debuginfo and to fill `self.upvars`. - if hir_typeck_results.closure_min_captures.get(&fn_def_id).is_some() { - let mut closure_env_projs = vec![]; - let mut closure_ty = self.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty; - if let ty::Ref(_, ty, _) = closure_ty.kind() { - closure_env_projs.push(ProjectionElem::Deref); - closure_ty = *ty; - } - let upvar_substs = match closure_ty.kind() { - ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs), - ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs), - _ => span_bug!(self.fn_span, "upvars with non-closure env ty {:?}", closure_ty), - }; - let def_id = self.def_id.as_local().unwrap(); - let capture_syms = tcx.symbols_for_closure_captures((def_id, fn_def_id)); - let capture_tys = upvar_substs.upvar_tys(); - let captures_with_tys = hir_typeck_results - .closure_min_captures_flattened(fn_def_id) - .zip(capture_tys.zip(capture_syms)); - - self.upvars = captures_with_tys - .enumerate() - .map(|(i, (captured_place, (ty, sym)))| { - let capture = captured_place.info.capture_kind; - let var_id = match captured_place.place.base { - HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, - _ => bug!("Expected an upvar"), - }; - - let mutability = captured_place.mutability; - - let mut projs = closure_env_projs.clone(); - projs.push(ProjectionElem::Field(Field::new(i), ty)); - match capture { - ty::UpvarCapture::ByValue => {} - ty::UpvarCapture::ByRef(..) => { - projs.push(ProjectionElem::Deref); - } - }; - - let use_place = Place { - local: ty::CAPTURE_STRUCT_LOCAL, - projection: tcx.mk_place_elems(&projs), - }; - self.var_debug_info.push(VarDebugInfo { - name: *sym, - source_info: SourceInfo::outermost(tcx_hir.span(var_id)), - value: VarDebugInfoContents::Place(use_place), - }); - - let capture = Capture { captured_place, use_place, mutability }; - (var_id, capture) - }) - .collect(); - } + self.insert_upvar_arg(); let mut scope = None; // Bind the argument patterns diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 3b11fc77d89..666b8e5cc7b 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -541,8 +541,9 @@ impl<'tcx> Cx<'tcx> { let def_id = def_id.expect_local(); let upvars = self - .typeck_results - .closure_min_captures_flattened(def_id) + .tcx + .closure_captures(def_id) + .iter() .zip(substs.upvar_tys()) .map(|(captured_place, ty)| { let upvars = self.capture_upvar(expr, captured_place, ty); From 0915d55d871e16b2fcb2fcf2759cd2b649b014e7 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 25 Feb 2023 22:51:57 +0000 Subject: [PATCH 3/4] Wrap more into into closure_typeinfo query. --- .../src/diagnostics/conflict_errors.rs | 23 +++-------- .../rustc_borrowck/src/diagnostics/mod.rs | 24 +++-------- .../src/diagnostics/mutability_errors.rs | 5 +-- .../src/type_check/input_output.rs | 6 +-- compiler/rustc_middle/src/arena.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/closure.rs | 40 +++++++++++++++---- compiler/rustc_middle/src/ty/mod.rs | 2 +- .../rustc_middle/src/ty/typeck_results.rs | 2 +- 9 files changed, 49 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 7a1066f6b58..cb97699d7d2 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -6,7 +6,7 @@ use rustc_errors::{ struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, }; use rustc_hir as hir; -use rustc_hir::def::Res; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem}; use rustc_infer::infer::TyCtxtInferExt; @@ -236,10 +236,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let ty = used_place.ty(self.body, self.infcx.tcx).ty; let needs_note = match ty.kind() { ty::Closure(id, _) => { - let tables = self.infcx.tcx.typeck(id.expect_local()); - let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(id.expect_local()); - - tables.closure_kind_origins().get(hir_id).is_none() + self.infcx.tcx.closure_kind_origin(id.expect_local()).is_none() } _ => true, }; @@ -1670,7 +1667,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { format!("`{}` would have to be valid for `{}`...", name, region_name), ); - let fn_hir_id = self.mir_hir_id(); err.span_label( drop_span, format!( @@ -1678,19 +1674,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { name, self.infcx .tcx - .hir() - .opt_name(fn_hir_id) + .opt_item_name(self.mir_def_id().to_def_id()) .map(|name| format!("function `{}`", name)) .unwrap_or_else(|| { - match &self - .infcx - .tcx - .typeck(self.mir_def_id()) - .node_type(fn_hir_id) - .kind() - { - ty::Closure(..) => "enclosing closure", - ty::Generator(..) => "enclosing generator", + match &self.infcx.tcx.def_kind(self.mir_def_id()) { + DefKind::Closure => "enclosing closure", + DefKind::Generator => "enclosing generator", kind => bug!("expected closure or generator, found {:?}", kind), } .to_string() diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index f5bd99f15ab..a99fd594a07 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -115,11 +115,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("add_moved_or_invoked_closure_note: closure={:?}", closure); if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() { let did = did.expect_local(); - let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did); - - if let Some((span, hir_place)) = - self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id) - { + if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { diag.span_note( *span, &format!( @@ -139,11 +135,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let Some(target) = target { if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() { let did = did.expect_local(); - let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did); - - if let Some((span, hir_place)) = - self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id) - { + if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { diag.span_note( *span, &format!( @@ -373,14 +365,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // // We know the field exists so it's safe to call operator[] and `unwrap` here. let def_id = def_id.expect_local(); - let var_id = self - .infcx - .tcx - .typeck(def_id) - .closure_min_captures_flattened(def_id) - .nth(field.index()) - .unwrap() - .get_root_variable(); + let var_id = + self.infcx.tcx.closure_captures(def_id)[field.index()].get_root_variable(); Some(self.infcx.tcx.hir().name(var_id).to_string()) } @@ -987,7 +973,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = expr { for (captured_place, place) in - self.infcx.tcx.typeck(def_id).closure_min_captures_flattened(def_id).zip(places) + self.infcx.tcx.closure_captures(def_id).iter().zip(places) { match place { Operand::Copy(place) | Operand::Move(place) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 9f37b915b77..f970d1615a4 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -901,10 +901,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err: &mut Diagnostic, ) { let tables = tcx.typeck(closure_local_def_id); - let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_local_def_id); - if let Some((span, closure_kind_origin)) = - &tables.closure_kind_origins().get(closure_hir_id) - { + if let Some((span, closure_kind_origin)) = tcx.closure_kind_origin(closure_local_def_id) { let reason = if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base { let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin); let root_hir_id = upvar_id.var_path.hir_id; diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index c6b78df9a5f..717020ea5b8 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -26,11 +26,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if !self.tcx().is_closure(mir_def_id.to_def_id()) { return; } - let Some(user_provided_poly_sig) = - self.tcx().typeck(mir_def_id).user_provided_sigs.get(&mir_def_id) - else { - return; - }; + let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id); // Instantiate the canonicalized variables from user-provided signature // (e.g., the `_` in the code above) with fresh variables. diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index d4019b5bf17..62e44b6298b 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -116,6 +116,7 @@ macro_rules! arena_types { [] bit_set_u32: rustc_index::bit_set::BitSet, [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>, [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap, + [] closure_kind_origin: (rustc_span::Span, rustc_middle::hir::place::Place<'tcx>), ]); ) } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 03d2eea7d4a..2bb8a8b5b73 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -475,7 +475,7 @@ rustc_queries! { } } - query closure_captures(key: LocalDefId) -> &'tcx [&'tcx ty::CapturedPlace<'tcx>] { + query closure_typeinfo(key: LocalDefId) -> ty::ClosureTypeInfo<'tcx> { desc { |tcx| "finding symbols for captures of closure `{}`", tcx.def_path_str(key.to_def_id()) diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 65df7204302..dc2bd54b7fe 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -6,7 +6,6 @@ use crate::{mir, ty}; use std::fmt::Write; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; -use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, LangItem}; use rustc_span::symbol::Ident; @@ -234,14 +233,39 @@ impl<'tcx> CapturedPlace<'tcx> { } } -fn closure_captures<'tcx>( - tcx: TyCtxt<'tcx>, - def: LocalDefId, -) -> &'tcx [&'tcx ty::CapturedPlace<'tcx>] { - let (DefKind::Closure | DefKind::Generator) = tcx.def_kind(def) else { return &[] }; +#[derive(Copy, Clone, Debug, HashStable)] +pub struct ClosureTypeInfo<'tcx> { + user_provided_sig: ty::CanonicalPolyFnSig<'tcx>, + captures: &'tcx [&'tcx ty::CapturedPlace<'tcx>], + kind_origin: Option<&'tcx (Span, HirPlace<'tcx>)>, +} + +fn closure_typeinfo<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ClosureTypeInfo<'tcx> { + debug_assert!(tcx.is_closure(def.to_def_id())); let typeck_results = tcx.typeck(def); + let user_provided_sig = typeck_results.user_provided_sigs[&def]; let captures = typeck_results.closure_min_captures_flattened(def); - tcx.arena.alloc_from_iter(captures) + let captures = tcx.arena.alloc_from_iter(captures); + let hir_id = tcx.hir().local_def_id_to_hir_id(def); + let kind_origin = typeck_results.closure_kind_origins().get(hir_id); + ClosureTypeInfo { user_provided_sig, captures, kind_origin } +} + +impl<'tcx> TyCtxt<'tcx> { + pub fn closure_kind_origin(self, def_id: LocalDefId) -> Option<&'tcx (Span, HirPlace<'tcx>)> { + self.closure_typeinfo(def_id).kind_origin + } + + pub fn closure_user_provided_sig(self, def_id: LocalDefId) -> ty::CanonicalPolyFnSig<'tcx> { + self.closure_typeinfo(def_id).user_provided_sig + } + + pub fn closure_captures(self, def_id: LocalDefId) -> &'tcx [&'tcx ty::CapturedPlace<'tcx>] { + if !self.is_closure(def_id.to_def_id()) { + return &[]; + }; + self.closure_typeinfo(def_id).captures + } } /// Return true if the `proj_possible_ancestor` represents an ancestor path @@ -434,5 +458,5 @@ impl BorrowKind { } pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { closure_captures, ..*providers } + *providers = ty::query::Providers { closure_typeinfo, ..*providers } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 17262a0be24..d8411042af0 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -73,7 +73,7 @@ pub use self::binding::BindingMode; pub use self::binding::BindingMode::*; pub use self::closure::{ is_ancestor_or_same_capture, place_to_string_for_capture, BorrowKind, CaptureInfo, - CapturedPlace, ClosureKind, MinCaptureInformationMap, MinCaptureList, + CapturedPlace, ClosureKind, ClosureTypeInfo, MinCaptureInformationMap, MinCaptureList, RootVariableMinCaptureList, UpvarCapture, UpvarCaptureMap, UpvarId, UpvarListMap, UpvarPath, CAPTURE_STRUCT_LOCAL, }; diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 9beaac87183..586958247fc 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -569,7 +569,7 @@ impl<'a, V> LocalTableInContext<'a, V> { self.data.contains_key(&id.local_id) } - pub fn get(&self, id: hir::HirId) -> Option<&V> { + pub fn get(&self, id: hir::HirId) -> Option<&'a V> { validate_hir_id_for_typeck_results(self.hir_owner, id); self.data.get(&id.local_id) } From cb51d2da7a590d230e8eae8e580ed8e8dee72bd6 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 26 Feb 2023 10:01:44 +0000 Subject: [PATCH 4/4] Avoid more calls to typeck. --- .../rustc_borrowck/src/universal_regions.rs | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index e058fe0db22..15d7613a812 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -18,7 +18,7 @@ use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; -use rustc_hir::{BodyOwnerKind, HirId}; +use rustc_hir::BodyOwnerKind; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::ty::fold::TypeFoldable; @@ -231,9 +231,7 @@ impl<'tcx> UniversalRegions<'tcx> { mir_def: ty::WithOptConstParam, param_env: ty::ParamEnv<'tcx>, ) -> Self { - let tcx = infcx.tcx; - let mir_hir_id = tcx.hir().local_def_id_to_hir_id(mir_def.did); - UniversalRegionsBuilder { infcx, mir_def, mir_hir_id, param_env }.build() + UniversalRegionsBuilder { infcx, mir_def, param_env }.build() } /// Given a reference to a closure type, extracts all the values @@ -390,7 +388,6 @@ impl<'tcx> UniversalRegions<'tcx> { struct UniversalRegionsBuilder<'cx, 'tcx> { infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>, mir_def: ty::WithOptConstParam, - mir_hir_id: HirId, param_env: ty::ParamEnv<'tcx>, } @@ -560,12 +557,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { match tcx.hir().body_owner_kind(self.mir_def.did) { BodyOwnerKind::Closure | BodyOwnerKind::Fn => { - let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id { - tcx.type_of(typeck_root_def_id).subst_identity() - } else { - let tables = tcx.typeck(self.mir_def.did); - tables.node_type(self.mir_hir_id) - }; + let defining_ty = tcx.type_of(self.mir_def.def_id_for_type_of()).subst_identity(); debug!("defining_ty (pre-replacement): {:?}", defining_ty); @@ -594,7 +586,18 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs); DefiningTy::Const(self.mir_def.did.to_def_id(), substs) } else { - let ty = tcx.typeck(self.mir_def.did).node_type(self.mir_hir_id); + // FIXME this line creates a dependency between borrowck and typeck. + // + // This is required for `AscribeUserType` canonical query, which will call + // `type_of(inline_const_def_id)`. That `type_of` would inject erased lifetimes + // into borrowck, which is ICE #78174. + // + // As a workaround, inline consts have an additional generic param (`ty` + // below), so that `type_of(inline_const_def_id).substs(substs)` uses the + // proper type with NLL infer vars. + let ty = tcx + .typeck(self.mir_def.did) + .node_type(tcx.local_def_id_to_hir_id(self.mir_def.did)); let substs = InlineConstSubsts::new( tcx, InlineConstSubstsParts { parent_substs: identity_substs, ty },