Auto merge of #108487 - cjgillot:no-typeck-mir, r=oli-obk
Avoid invoking typeck from borrowck This PR attempts to reduce direct dependencies between typeck and MIR-related queries. The goal is to have all the information transit either through THIR or through dedicated queries that avoid depending on the whole `TypeckResults`. In a first commit, we store the type information that MIR building requires into THIR. This avoids edges between mir_built and typeck. In the second and third commit, we wrap informations around closures (upvars, kind origin and user-provided signature) to avoid borrowck depending on typeck information. There should be a single remaining borrowck -> typeck edge in the good path, due to inline consts.
This commit is contained in:
commit
6290ae92b2
20 changed files with 223 additions and 207 deletions
|
@ -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;
|
||||
|
@ -47,8 +47,6 @@ pub(crate) fn mir_built(
|
|||
|
||||
/// Construct the MIR for a given `DefId`.
|
||||
fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> 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<LocalDefId>) -> 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),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -158,13 +155,13 @@ struct BlockContext(Vec<BlockFrame>);
|
|||
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<LocalDefId>,
|
||||
def_id: DefId,
|
||||
hir_id: hir::HirId,
|
||||
parent_module: DefId,
|
||||
|
@ -434,6 +431,7 @@ fn construct_fn<'tcx>(
|
|||
fn_def: ty::WithOptConstParam<LocalDefId>,
|
||||
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,
|
||||
|
@ -529,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);
|
||||
|
@ -563,6 +550,7 @@ fn construct_const<'a, 'tcx>(
|
|||
def: ty::WithOptConstParam<LocalDefId>,
|
||||
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 +574,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 +603,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 {
|
||||
|
@ -728,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(),
|
||||
|
@ -780,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<ParamId, Param<'tcx>>,
|
||||
argument_scope: region::Scope,
|
||||
expr: &Expr<'tcx>,
|
||||
|
@ -809,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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -82,9 +82,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,
|
||||
|
@ -92,7 +113,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),
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue