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
|
@ -6,7 +6,7 @@ use rustc_errors::{
|
||||||
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
|
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
|
||||||
};
|
};
|
||||||
use rustc_hir as hir;
|
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::intravisit::{walk_block, walk_expr, Visitor};
|
||||||
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
|
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
|
||||||
use rustc_infer::infer::TyCtxtInferExt;
|
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 ty = used_place.ty(self.body, self.infcx.tcx).ty;
|
||||||
let needs_note = match ty.kind() {
|
let needs_note = match ty.kind() {
|
||||||
ty::Closure(id, _) => {
|
ty::Closure(id, _) => {
|
||||||
let tables = self.infcx.tcx.typeck(id.expect_local());
|
self.infcx.tcx.closure_kind_origin(id.expect_local()).is_none()
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
_ => true,
|
_ => true,
|
||||||
};
|
};
|
||||||
|
@ -1670,7 +1667,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
format!("`{}` would have to be valid for `{}`...", name, region_name),
|
format!("`{}` would have to be valid for `{}`...", name, region_name),
|
||||||
);
|
);
|
||||||
|
|
||||||
let fn_hir_id = self.mir_hir_id();
|
|
||||||
err.span_label(
|
err.span_label(
|
||||||
drop_span,
|
drop_span,
|
||||||
format!(
|
format!(
|
||||||
|
@ -1678,19 +1674,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
name,
|
name,
|
||||||
self.infcx
|
self.infcx
|
||||||
.tcx
|
.tcx
|
||||||
.hir()
|
.opt_item_name(self.mir_def_id().to_def_id())
|
||||||
.opt_name(fn_hir_id)
|
|
||||||
.map(|name| format!("function `{}`", name))
|
.map(|name| format!("function `{}`", name))
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
match &self
|
match &self.infcx.tcx.def_kind(self.mir_def_id()) {
|
||||||
.infcx
|
DefKind::Closure => "enclosing closure",
|
||||||
.tcx
|
DefKind::Generator => "enclosing generator",
|
||||||
.typeck(self.mir_def_id())
|
|
||||||
.node_type(fn_hir_id)
|
|
||||||
.kind()
|
|
||||||
{
|
|
||||||
ty::Closure(..) => "enclosing closure",
|
|
||||||
ty::Generator(..) => "enclosing generator",
|
|
||||||
kind => bug!("expected closure or generator, found {:?}", kind),
|
kind => bug!("expected closure or generator, found {:?}", kind),
|
||||||
}
|
}
|
||||||
.to_string()
|
.to_string()
|
||||||
|
|
|
@ -115,11 +115,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
|
debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
|
||||||
if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
|
if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
|
||||||
let did = did.expect_local();
|
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.closure_kind_origin(did) {
|
||||||
|
|
||||||
if let Some((span, hir_place)) =
|
|
||||||
self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
|
|
||||||
{
|
|
||||||
diag.span_note(
|
diag.span_note(
|
||||||
*span,
|
*span,
|
||||||
&format!(
|
&format!(
|
||||||
|
@ -139,11 +135,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
if let Some(target) = target {
|
if let Some(target) = target {
|
||||||
if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
|
if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
|
||||||
let did = did.expect_local();
|
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.closure_kind_origin(did) {
|
||||||
|
|
||||||
if let Some((span, hir_place)) =
|
|
||||||
self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
|
|
||||||
{
|
|
||||||
diag.span_note(
|
diag.span_note(
|
||||||
*span,
|
*span,
|
||||||
&format!(
|
&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.
|
// We know the field exists so it's safe to call operator[] and `unwrap` here.
|
||||||
let def_id = def_id.expect_local();
|
let def_id = def_id.expect_local();
|
||||||
let var_id = self
|
let var_id =
|
||||||
.infcx
|
self.infcx.tcx.closure_captures(def_id)[field.index()].get_root_variable();
|
||||||
.tcx
|
|
||||||
.typeck(def_id)
|
|
||||||
.closure_min_captures_flattened(def_id)
|
|
||||||
.nth(field.index())
|
|
||||||
.unwrap()
|
|
||||||
.get_root_variable();
|
|
||||||
|
|
||||||
Some(self.infcx.tcx.hir().name(var_id).to_string())
|
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);
|
debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
|
||||||
if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = expr {
|
if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = expr {
|
||||||
for (captured_place, place) in
|
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 {
|
match place {
|
||||||
Operand::Copy(place) | Operand::Move(place)
|
Operand::Copy(place) | Operand::Move(place)
|
||||||
|
|
|
@ -901,10 +901,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
) {
|
) {
|
||||||
let tables = tcx.typeck(closure_local_def_id);
|
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)) = tcx.closure_kind_origin(closure_local_def_id) {
|
||||||
if let Some((span, closure_kind_origin)) =
|
|
||||||
&tables.closure_kind_origins().get(closure_hir_id)
|
|
||||||
{
|
|
||||||
let reason = if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base {
|
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 upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin);
|
||||||
let root_hir_id = upvar_id.var_path.hir_id;
|
let root_hir_id = upvar_id.var_path.hir_id;
|
||||||
|
|
|
@ -202,14 +202,14 @@ fn do_mir_borrowck<'tcx>(
|
||||||
let mut errors = error::BorrowckErrors::new(infcx.tcx);
|
let mut errors = error::BorrowckErrors::new(infcx.tcx);
|
||||||
|
|
||||||
// Gather the upvars of a closure, if any.
|
// Gather the upvars of a closure, if any.
|
||||||
let tables = tcx.typeck_opt_const_arg(def);
|
if let Some(e) = input_body.tainted_by_errors {
|
||||||
if let Some(e) = tables.tainted_by_errors {
|
|
||||||
infcx.set_tainted_by_errors(e);
|
infcx.set_tainted_by_errors(e);
|
||||||
errors.set_tainted_by_errors(e);
|
errors.set_tainted_by_errors(e);
|
||||||
}
|
}
|
||||||
let upvars: Vec<_> = tables
|
let upvars: Vec<_> = tcx
|
||||||
.closure_min_captures_flattened(def.did)
|
.closure_captures(def.did)
|
||||||
.map(|captured_place| {
|
.iter()
|
||||||
|
.map(|&captured_place| {
|
||||||
let capture = captured_place.info.capture_kind;
|
let capture = captured_place.info.capture_kind;
|
||||||
let by_ref = match capture {
|
let by_ref = match capture {
|
||||||
ty::UpvarCapture::ByValue => false,
|
ty::UpvarCapture::ByValue => false,
|
||||||
|
|
|
@ -26,11 +26,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
if !self.tcx().is_closure(mir_def_id.to_def_id()) {
|
if !self.tcx().is_closure(mir_def_id.to_def_id()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let Some(user_provided_poly_sig) =
|
let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id);
|
||||||
self.tcx().typeck(mir_def_id).user_provided_sigs.get(&mir_def_id)
|
|
||||||
else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Instantiate the canonicalized variables from user-provided signature
|
// Instantiate the canonicalized variables from user-provided signature
|
||||||
// (e.g., the `_` in the code above) with fresh variables.
|
// (e.g., the `_` in the code above) with fresh variables.
|
||||||
|
|
|
@ -18,7 +18,7 @@ use rustc_errors::Diagnostic;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_hir::{BodyOwnerKind, HirId};
|
use rustc_hir::BodyOwnerKind;
|
||||||
use rustc_index::vec::{Idx, IndexVec};
|
use rustc_index::vec::{Idx, IndexVec};
|
||||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||||
use rustc_middle::ty::fold::TypeFoldable;
|
use rustc_middle::ty::fold::TypeFoldable;
|
||||||
|
@ -231,9 +231,7 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||||
mir_def: ty::WithOptConstParam<LocalDefId>,
|
mir_def: ty::WithOptConstParam<LocalDefId>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let tcx = infcx.tcx;
|
UniversalRegionsBuilder { infcx, mir_def, param_env }.build()
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a reference to a closure type, extracts all the values
|
/// Given a reference to a closure type, extracts all the values
|
||||||
|
@ -390,7 +388,6 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||||
struct UniversalRegionsBuilder<'cx, 'tcx> {
|
struct UniversalRegionsBuilder<'cx, 'tcx> {
|
||||||
infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>,
|
infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>,
|
||||||
mir_def: ty::WithOptConstParam<LocalDefId>,
|
mir_def: ty::WithOptConstParam<LocalDefId>,
|
||||||
mir_hir_id: HirId,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
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) {
|
match tcx.hir().body_owner_kind(self.mir_def.did) {
|
||||||
BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
|
BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
|
||||||
let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id {
|
let defining_ty = tcx.type_of(self.mir_def.def_id_for_type_of()).subst_identity();
|
||||||
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)
|
|
||||||
};
|
|
||||||
|
|
||||||
debug!("defining_ty (pre-replacement): {:?}", defining_ty);
|
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);
|
self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
|
||||||
DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
|
DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
|
||||||
} else {
|
} 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(
|
let substs = InlineConstSubsts::new(
|
||||||
tcx,
|
tcx,
|
||||||
InlineConstSubstsParts { parent_substs: identity_substs, ty },
|
InlineConstSubstsParts { parent_substs: identity_substs, ty },
|
||||||
|
|
|
@ -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
|
// FIXME this should be more descriptive i.e. CapturePlace instead of CapturedVar
|
||||||
// https://github.com/rust-lang/project-rfc-2229/issues/46
|
// https://github.com/rust-lang/project-rfc-2229/issues/46
|
||||||
if let Some(local_def_id) = def_id.as_local() {
|
if let Some(local_def_id) = def_id.as_local() {
|
||||||
let tables = self.ecx.tcx.typeck(local_def_id);
|
let captures = self.ecx.tcx.closure_captures(local_def_id);
|
||||||
if let Some(captured_place) =
|
if let Some(captured_place) = captures.get(field) {
|
||||||
tables.closure_min_captures_flattened(local_def_id).nth(field)
|
|
||||||
{
|
|
||||||
// Sometimes the index is beyond the number of upvars (seen
|
// Sometimes the index is beyond the number of upvars (seen
|
||||||
// for a generator).
|
// for a generator).
|
||||||
let var_hir_id = captured_place.get_root_variable();
|
let var_hir_id = captured_place.get_root_variable();
|
||||||
|
|
|
@ -526,10 +526,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
|
PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
|
||||||
base => bug!("Expected upvar, found={:?}", base),
|
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 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 mutability = self.determine_capture_mutability(&typeck_results, &place);
|
||||||
let min_cap_list = vec![ty::CapturedPlace {
|
let min_cap_list = vec![ty::CapturedPlace {
|
||||||
|
var_ident,
|
||||||
place,
|
place,
|
||||||
info: capture_info,
|
info: capture_info,
|
||||||
mutability,
|
mutability,
|
||||||
|
@ -628,6 +630,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
if !ancestor_found {
|
if !ancestor_found {
|
||||||
let mutability = self.determine_capture_mutability(&typeck_results, &place);
|
let mutability = self.determine_capture_mutability(&typeck_results, &place);
|
||||||
let captured_place = ty::CapturedPlace {
|
let captured_place = ty::CapturedPlace {
|
||||||
|
var_ident,
|
||||||
place,
|
place,
|
||||||
info: updated_capture_info,
|
info: updated_capture_info,
|
||||||
mutability,
|
mutability,
|
||||||
|
|
|
@ -116,6 +116,7 @@ macro_rules! arena_types {
|
||||||
[] bit_set_u32: rustc_index::bit_set::BitSet<u32>,
|
[] bit_set_u32: rustc_index::bit_set::BitSet<u32>,
|
||||||
[] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>,
|
[] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>,
|
||||||
[decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap,
|
[decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap,
|
||||||
|
[] closure_kind_origin: (rustc_span::Span, rustc_middle::hir::place::Place<'tcx>),
|
||||||
]);
|
]);
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -902,6 +902,11 @@ impl<'hir> Map<'hir> {
|
||||||
self.opt_ident(id).map(|ident| ident.span)
|
self.opt_ident(id).map(|ident| ident.span)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn ident(self, id: HirId) -> Ident {
|
||||||
|
self.opt_ident(id).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn opt_name(self, id: HirId) -> Option<Symbol> {
|
pub fn opt_name(self, id: HirId) -> Option<Symbol> {
|
||||||
self.opt_ident(id).map(|ident| ident.name)
|
self.opt_ident(id).map(|ident| ident.name)
|
||||||
|
|
|
@ -475,14 +475,10 @@ rustc_queries! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
query symbols_for_closure_captures(
|
query closure_typeinfo(key: LocalDefId) -> ty::ClosureTypeInfo<'tcx> {
|
||||||
key: (LocalDefId, LocalDefId)
|
|
||||||
) -> &'tcx Vec<rustc_span::Symbol> {
|
|
||||||
arena_cache
|
|
||||||
desc {
|
desc {
|
||||||
|tcx| "finding symbols for captures of closure `{}` in `{}`",
|
|tcx| "finding symbols for captures of closure `{}`",
|
||||||
tcx.def_path_str(key.1.to_def_id()),
|
tcx.def_path_str(key.to_def_id())
|
||||||
tcx.def_path_str(key.0.to_def_id())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ use rustc_middle::mir::interpret::AllocId;
|
||||||
use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp};
|
use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp};
|
||||||
use rustc_middle::ty::adjustment::PointerCast;
|
use rustc_middle::ty::adjustment::PointerCast;
|
||||||
use rustc_middle::ty::subst::SubstsRef;
|
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_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation};
|
||||||
use rustc_span::def_id::LocalDefId;
|
use rustc_span::def_id::LocalDefId;
|
||||||
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
|
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
|
||||||
|
@ -32,7 +32,12 @@ use std::ops::Index;
|
||||||
pub mod visit;
|
pub mod visit;
|
||||||
|
|
||||||
macro_rules! thir_with_elements {
|
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! {
|
newtype_index! {
|
||||||
#[derive(HashStable)]
|
#[derive(HashStable)]
|
||||||
|
@ -46,14 +51,20 @@ macro_rules! thir_with_elements {
|
||||||
/// This can be indexed directly by any THIR index (e.g. [`ExprId`]).
|
/// This can be indexed directly by any THIR index (e.g. [`ExprId`]).
|
||||||
#[derive(Debug, HashStable, Clone)]
|
#[derive(Debug, HashStable, Clone)]
|
||||||
pub struct Thir<'tcx> {
|
pub struct Thir<'tcx> {
|
||||||
|
$(
|
||||||
|
pub $field_name: $field_ty,
|
||||||
|
)*
|
||||||
$(
|
$(
|
||||||
pub $name: IndexVec<$id, $value>,
|
pub $name: IndexVec<$id, $value>,
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Thir<'tcx> {
|
impl<'tcx> Thir<'tcx> {
|
||||||
pub fn new() -> Thir<'tcx> {
|
pub fn new($($field_name: $field_ty,)*) -> Thir<'tcx> {
|
||||||
Thir {
|
Thir {
|
||||||
|
$(
|
||||||
|
$field_name,
|
||||||
|
)*
|
||||||
$(
|
$(
|
||||||
$name: IndexVec::new(),
|
$name: IndexVec::new(),
|
||||||
)*
|
)*
|
||||||
|
@ -75,6 +86,9 @@ macro_rules! thir_with_elements {
|
||||||
pub const UPVAR_ENV_PARAM: ParamId = ParamId::from_u32(0);
|
pub const UPVAR_ENV_PARAM: ParamId = ParamId::from_u32(0);
|
||||||
|
|
||||||
thir_with_elements! {
|
thir_with_elements! {
|
||||||
|
body_type: BodyTy<'tcx>,
|
||||||
|
|
||||||
|
@elements:
|
||||||
arms: ArmId => Arm<'tcx> => "a{}",
|
arms: ArmId => Arm<'tcx> => "a{}",
|
||||||
blocks: BlockId => Block => "b{}",
|
blocks: BlockId => Block => "b{}",
|
||||||
exprs: ExprId => Expr<'tcx> => "e{}",
|
exprs: ExprId => Expr<'tcx> => "e{}",
|
||||||
|
@ -82,6 +96,12 @@ thir_with_elements! {
|
||||||
params: ParamId => Param<'tcx> => "p{}",
|
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.
|
/// Description of a type-checked function parameter.
|
||||||
#[derive(Clone, Debug, HashStable)]
|
#[derive(Clone, Debug, HashStable)]
|
||||||
pub struct Param<'tcx> {
|
pub struct Param<'tcx> {
|
||||||
|
|
|
@ -5,10 +5,10 @@ use crate::{mir, ty};
|
||||||
|
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use hir::LangItem;
|
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||||
use rustc_hir as hir;
|
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
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 rustc_span::{Span, Symbol};
|
||||||
|
|
||||||
use super::{Ty, TyCtxt};
|
use super::{Ty, TyCtxt};
|
||||||
|
@ -129,6 +129,9 @@ impl<'tcx> ClosureKind {
|
||||||
#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||||
#[derive(TypeFoldable, TypeVisitable)]
|
#[derive(TypeFoldable, TypeVisitable)]
|
||||||
pub struct CapturedPlace<'tcx> {
|
pub struct CapturedPlace<'tcx> {
|
||||||
|
/// Name and span where the binding happens.
|
||||||
|
pub var_ident: Ident,
|
||||||
|
|
||||||
/// The `Place` that is captured.
|
/// The `Place` that is captured.
|
||||||
pub place: HirPlace<'tcx>,
|
pub place: HirPlace<'tcx>,
|
||||||
|
|
||||||
|
@ -148,12 +151,8 @@ impl<'tcx> CapturedPlace<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a symbol of the captured upvar, which looks like `name__field1__field2`.
|
/// Returns a symbol of the captured upvar, which looks like `name__field1__field2`.
|
||||||
fn to_symbol(&self, tcx: TyCtxt<'tcx>) -> Symbol {
|
pub fn to_symbol(&self) -> Symbol {
|
||||||
let hir_id = match self.place.base {
|
let mut symbol = self.var_ident.to_string();
|
||||||
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();
|
|
||||||
|
|
||||||
let mut ty = self.place.base_ty;
|
let mut ty = self.place.base_ty;
|
||||||
for proj in self.place.projections.iter() {
|
for proj in self.place.projections.iter() {
|
||||||
|
@ -169,11 +168,7 @@ impl<'tcx> CapturedPlace<'tcx> {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
ty => {
|
ty => {
|
||||||
span_bug!(
|
bug!("Unexpected type {:?} for `Field` projection", ty)
|
||||||
self.get_capture_kind_span(tcx),
|
|
||||||
"Unexpected type {:?} for `Field` projection",
|
|
||||||
ty
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -238,10 +233,39 @@ impl<'tcx> CapturedPlace<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn symbols_for_closure_captures(tcx: TyCtxt<'_>, def_id: (LocalDefId, LocalDefId)) -> Vec<Symbol> {
|
#[derive(Copy, Clone, Debug, HashStable)]
|
||||||
let typeck_results = tcx.typeck(def_id.0);
|
pub struct ClosureTypeInfo<'tcx> {
|
||||||
let captures = typeck_results.closure_min_captures_flattened(def_id.1);
|
user_provided_sig: ty::CanonicalPolyFnSig<'tcx>,
|
||||||
captures.into_iter().map(|captured_place| captured_place.to_symbol(tcx)).collect()
|
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);
|
||||||
|
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
|
/// 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) {
|
pub fn provide(providers: &mut ty::query::Providers) {
|
||||||
*providers = ty::query::Providers { symbols_for_closure_captures, ..*providers }
|
*providers = ty::query::Providers { closure_typeinfo, ..*providers }
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ pub use self::binding::BindingMode;
|
||||||
pub use self::binding::BindingMode::*;
|
pub use self::binding::BindingMode::*;
|
||||||
pub use self::closure::{
|
pub use self::closure::{
|
||||||
is_ancestor_or_same_capture, place_to_string_for_capture, BorrowKind, CaptureInfo,
|
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,
|
RootVariableMinCaptureList, UpvarCapture, UpvarCaptureMap, UpvarId, UpvarListMap, UpvarPath,
|
||||||
CAPTURE_STRUCT_LOCAL,
|
CAPTURE_STRUCT_LOCAL,
|
||||||
};
|
};
|
||||||
|
|
|
@ -263,6 +263,7 @@ TrivialTypeTraversalAndLiftImpls! {
|
||||||
crate::ty::UniverseIndex,
|
crate::ty::UniverseIndex,
|
||||||
crate::ty::Variance,
|
crate::ty::Variance,
|
||||||
::rustc_span::Span,
|
::rustc_span::Span,
|
||||||
|
::rustc_span::symbol::Ident,
|
||||||
::rustc_errors::ErrorGuaranteed,
|
::rustc_errors::ErrorGuaranteed,
|
||||||
Field,
|
Field,
|
||||||
interpret::Scalar,
|
interpret::Scalar,
|
||||||
|
|
|
@ -569,7 +569,7 @@ impl<'a, V> LocalTableInContext<'a, V> {
|
||||||
self.data.contains_key(&id.local_id)
|
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);
|
validate_hir_id_for_typeck_results(self.hir_owner, id);
|
||||||
self.data.get(&id.local_id)
|
self.data.get(&id.local_id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ use rustc_middle::mir::*;
|
||||||
use rustc_middle::thir::{
|
use rustc_middle::thir::{
|
||||||
self, BindingMode, Expr, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, 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::symbol::sym;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_span::Symbol;
|
use rustc_span::Symbol;
|
||||||
|
@ -47,8 +47,6 @@ pub(crate) fn mir_built(
|
||||||
|
|
||||||
/// Construct the MIR for a given `DefId`.
|
/// Construct the MIR for a given `DefId`.
|
||||||
fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
|
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.
|
// 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
|
// 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
|
// 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) {
|
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)) => {
|
Ok((thir, expr)) => {
|
||||||
// We ran all queries that depended on THIR at the beginning
|
// We ran all queries that depended on THIR at the beginning
|
||||||
// of `mir_build`, so now we can steal it
|
// of `mir_build`, so now we can steal it
|
||||||
let thir = thir.steal();
|
let thir = thir.steal();
|
||||||
|
|
||||||
if body_owner_kind.is_fn_or_closure() {
|
match thir.body_type {
|
||||||
construct_fn(tcx, def, &thir, expr)
|
thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, &thir, expr, fn_sig),
|
||||||
} else {
|
thir::BodyTy::Const(ty) => construct_const(tcx, def, &thir, expr, ty),
|
||||||
construct_const(tcx, def, &thir, expr)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -158,13 +155,13 @@ struct BlockContext(Vec<BlockFrame>);
|
||||||
struct Builder<'a, 'tcx> {
|
struct Builder<'a, 'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
infcx: InferCtxt<'tcx>,
|
infcx: InferCtxt<'tcx>,
|
||||||
typeck_results: &'tcx TypeckResults<'tcx>,
|
|
||||||
region_scope_tree: &'tcx region::ScopeTree,
|
region_scope_tree: &'tcx region::ScopeTree,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
|
||||||
thir: &'a Thir<'tcx>,
|
thir: &'a Thir<'tcx>,
|
||||||
cfg: CFG<'tcx>,
|
cfg: CFG<'tcx>,
|
||||||
|
|
||||||
|
def: ty::WithOptConstParam<LocalDefId>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
hir_id: hir::HirId,
|
hir_id: hir::HirId,
|
||||||
parent_module: DefId,
|
parent_module: DefId,
|
||||||
|
@ -434,6 +431,7 @@ fn construct_fn<'tcx>(
|
||||||
fn_def: ty::WithOptConstParam<LocalDefId>,
|
fn_def: ty::WithOptConstParam<LocalDefId>,
|
||||||
thir: &Thir<'tcx>,
|
thir: &Thir<'tcx>,
|
||||||
expr: ExprId,
|
expr: ExprId,
|
||||||
|
fn_sig: ty::FnSig<'tcx>,
|
||||||
) -> Body<'tcx> {
|
) -> Body<'tcx> {
|
||||||
let span = tcx.def_span(fn_def.did);
|
let span = tcx.def_span(fn_def.did);
|
||||||
let fn_id = tcx.hir().local_def_id_to_hir_id(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
|
.output
|
||||||
.span();
|
.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 {
|
let safety = match fn_sig.unsafety {
|
||||||
hir::Unsafety::Normal => Safety::Safe,
|
hir::Unsafety::Normal => Safety::Safe,
|
||||||
hir::Unsafety::Unsafe => Safety::FnUnsafe,
|
hir::Unsafety::Unsafe => Safety::FnUnsafe,
|
||||||
|
@ -529,13 +522,7 @@ fn construct_fn<'tcx>(
|
||||||
let return_block =
|
let return_block =
|
||||||
unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| {
|
unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| {
|
||||||
Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
|
Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
|
||||||
builder.args_and_body(
|
builder.args_and_body(START_BLOCK, arguments, arg_scope, &thir[expr])
|
||||||
START_BLOCK,
|
|
||||||
fn_def.did,
|
|
||||||
arguments,
|
|
||||||
arg_scope,
|
|
||||||
&thir[expr],
|
|
||||||
)
|
|
||||||
}))
|
}))
|
||||||
}));
|
}));
|
||||||
let source_info = builder.source_info(fn_end);
|
let source_info = builder.source_info(fn_end);
|
||||||
|
@ -563,6 +550,7 @@ fn construct_const<'a, 'tcx>(
|
||||||
def: ty::WithOptConstParam<LocalDefId>,
|
def: ty::WithOptConstParam<LocalDefId>,
|
||||||
thir: &'a Thir<'tcx>,
|
thir: &'a Thir<'tcx>,
|
||||||
expr: ExprId,
|
expr: ExprId,
|
||||||
|
const_ty: Ty<'tcx>,
|
||||||
) -> Body<'tcx> {
|
) -> Body<'tcx> {
|
||||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
|
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),
|
_ => 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 infcx = tcx.infer_ctxt().build();
|
||||||
let mut builder = Builder::new(
|
let mut builder = Builder::new(
|
||||||
thir,
|
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
|
/// 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.
|
/// with type errors, but normal MIR construction can't handle that in general.
|
||||||
fn construct_error(
|
fn construct_error(tcx: TyCtxt<'_>, def: LocalDefId, err: ErrorGuaranteed) -> Body<'_> {
|
||||||
tcx: TyCtxt<'_>,
|
|
||||||
def: LocalDefId,
|
|
||||||
body_owner_kind: hir::BodyOwnerKind,
|
|
||||||
err: ErrorGuaranteed,
|
|
||||||
) -> Body<'_> {
|
|
||||||
let span = tcx.def_span(def);
|
let span = tcx.def_span(def);
|
||||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def);
|
let hir_id = tcx.hir().local_def_id_to_hir_id(def);
|
||||||
let generator_kind = tcx.generator_kind(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 ty = tcx.ty_error(err);
|
||||||
let num_params = match body_owner_kind {
|
let num_params = match body_owner_kind {
|
||||||
|
@ -728,9 +698,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
thir,
|
thir,
|
||||||
tcx,
|
tcx,
|
||||||
infcx,
|
infcx,
|
||||||
typeck_results: tcx.typeck_opt_const_arg(def),
|
|
||||||
region_scope_tree: tcx.region_scope_tree(def.did),
|
region_scope_tree: tcx.region_scope_tree(def.did),
|
||||||
param_env,
|
param_env,
|
||||||
|
def,
|
||||||
def_id: def.did.to_def_id(),
|
def_id: def.did.to_def_id(),
|
||||||
hir_id,
|
hir_id,
|
||||||
parent_module: tcx.parent_module(hir_id).to_def_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.var_debug_info,
|
||||||
self.fn_span,
|
self.fn_span,
|
||||||
self.generator_kind,
|
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(
|
fn args_and_body(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
fn_def_id: LocalDefId,
|
|
||||||
arguments: &IndexVec<ParamId, Param<'tcx>>,
|
arguments: &IndexVec<ParamId, Param<'tcx>>,
|
||||||
argument_scope: region::Scope,
|
argument_scope: region::Scope,
|
||||||
expr: &Expr<'tcx>,
|
expr: &Expr<'tcx>,
|
||||||
|
@ -809,69 +843,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let tcx = self.tcx;
|
self.insert_upvar_arg();
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut scope = None;
|
let mut scope = None;
|
||||||
// Bind the argument patterns
|
// Bind the argument patterns
|
||||||
|
|
|
@ -541,8 +541,9 @@ impl<'tcx> Cx<'tcx> {
|
||||||
let def_id = def_id.expect_local();
|
let def_id = def_id.expect_local();
|
||||||
|
|
||||||
let upvars = self
|
let upvars = self
|
||||||
.typeck_results
|
.tcx
|
||||||
.closure_min_captures_flattened(def_id)
|
.closure_captures(def_id)
|
||||||
|
.iter()
|
||||||
.zip(substs.upvar_tys())
|
.zip(substs.upvar_tys())
|
||||||
.map(|(captured_place, ty)| {
|
.map(|(captured_place, ty)| {
|
||||||
let upvars = self.capture_upvar(expr, 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 typeck_results = tcx.typeck_opt_const_arg(def);
|
||||||
let did = def.did;
|
let did = def.did;
|
||||||
let hir = tcx.hir();
|
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 {
|
Cx {
|
||||||
tcx,
|
tcx,
|
||||||
thir: Thir::new(),
|
thir: Thir::new(body_type),
|
||||||
param_env: tcx.param_env(def.did),
|
param_env: tcx.param_env(def.did),
|
||||||
region_scope_tree: tcx.region_scope_tree(def.did),
|
region_scope_tree: tcx.region_scope_tree(def.did),
|
||||||
typeck_results,
|
typeck_results,
|
||||||
|
@ -92,7 +113,7 @@ impl<'tcx> Cx<'tcx> {
|
||||||
body_owner: did.to_def_id(),
|
body_owner: did.to_def_id(),
|
||||||
adjustment_span: None,
|
adjustment_span: None,
|
||||||
apply_adjustments: hir
|
apply_adjustments: hir
|
||||||
.attrs(hir.local_def_id_to_hir_id(did))
|
.attrs(hir_id)
|
||||||
.iter()
|
.iter()
|
||||||
.all(|attr| attr.name_or_empty() != rustc_span::sym::custom_mir),
|
.all(|attr| attr.name_or_empty() != rustc_span::sym::custom_mir),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
DefId(0:3 ~ thir_flat[45a6]::main):
|
DefId(0:3 ~ thir_flat[45a6]::main):
|
||||||
Thir {
|
Thir {
|
||||||
|
body_type: Fn(
|
||||||
|
([]; c_variadic: false)->(),
|
||||||
|
),
|
||||||
arms: [],
|
arms: [],
|
||||||
blocks: [
|
blocks: [
|
||||||
Block {
|
Block {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue