extract the writeback code for anon types into InferCtxt

No functional change.
This commit is contained in:
Niko Matsakis 2017-12-09 10:56:20 -05:00
parent 8e64ba83be
commit 7f50e7ca85
2 changed files with 225 additions and 132 deletions

View file

@ -11,12 +11,13 @@
use hir::def_id::DefId;
use infer::{self, InferCtxt, InferOk, TypeVariableOrigin};
use infer::outlives::free_region_map::FreeRegionRelations;
use rustc_data_structures::fx::FxHashMap;
use syntax::ast;
use traits::{self, PredicateObligation};
use ty::{self, Ty};
use ty::fold::{BottomUpFolder, TypeFoldable};
use ty::outlives::Component;
use ty::subst::Substs;
use ty::subst::{Kind, Substs};
use util::nodemap::DefIdMap;
pub type AnonTypeMap<'tcx> = DefIdMap<AnonTypeDecl<'tcx>>;
@ -375,6 +376,106 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
}
}
/// Given the fully resolved, instantiated type for an anonymous
/// type, i.e., the value of an inference variable like C1 or C2
/// (*), computes the "definition type" for an abstract type
/// definition -- that is, the inferred value of `Foo1<'x>` or
/// `Foo2<'x>` that we would conceptually use in its definition:
///
/// abstract type Foo1<'x>: Bar<'x> = AAA; <-- this type AAA
/// abstract type Foo2<'x>: Bar<'x> = BBB; <-- or this type BBB
/// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
///
/// Note that these values are defined in terms of a distinct set of
/// generic parameters (`'x` instead of `'a`) from C1 or C2. The main
/// purpose of this function is to do that translation.
///
/// (*) C1 and C2 were introduced in the comments on
/// `constrain_anon_types`. Read that comment for more context.
///
/// # Parameters
///
/// - `def_id`, the `impl Trait` type
/// - `anon_defn`, the anonymous definition created in `instantiate_anon_types`
/// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
/// `anon_defn.concrete_ty`
pub fn infer_anon_definition_from_instantiation(
&self,
def_id: DefId,
anon_defn: &AnonTypeDecl<'tcx>,
instantiated_ty: Ty<'gcx>,
) -> Ty<'gcx> {
debug!(
"infer_anon_definition_from_instantiation(instantiated_ty={:?})",
instantiated_ty
);
let gcx = self.tcx.global_tcx();
// Use substs to build up a reverse map from regions to their
// identity mappings. This is necessary because of `impl
// Trait` lifetimes are computed by replacing existing
// lifetimes with 'static and remapping only those used in the
// `impl Trait` return type, resulting in the parameters
// shifting.
let id_substs = Substs::identity_for_item(gcx, def_id);
let map: FxHashMap<Kind<'tcx>, Kind<'gcx>> = anon_defn
.substs
.iter()
.enumerate()
.map(|(index, subst)| (*subst, id_substs[index]))
.collect();
// Convert the type from the function into a type valid outside
// the function, by replacing invalid regions with 'static,
// after producing an error for each of them.
let definition_ty = gcx.fold_regions(&instantiated_ty, &mut false, |r, _| {
match *r {
// 'static and early-bound regions are valid.
ty::ReStatic | ty::ReEmpty => r,
// All other regions, we map them appropriately to their adjusted
// indices, erroring if we find any lifetimes that were not mapped
// into the new set.
_ => if let Some(r1) = map.get(&Kind::from(r)).and_then(|k| k.as_region()) {
r1
} else {
// No mapping was found. This means that
// it is either a disallowed lifetime,
// which will be caught by regionck, or it
// is a region in a non-upvar closure
// generic, which is explicitly
// allowed. If that surprises you, read
// on.
//
// The case of closure is a somewhat
// subtle (read: hacky) consideration. The
// problem is that our closure types
// currently include all the lifetime
// parameters declared on the enclosing
// function, even if they are unused by
// the closure itself. We can't readily
// filter them out, so here we replace
// those values with `'empty`. This can't
// really make a difference to the rest of
// the compiler; those regions are ignored
// for the outlives relation, and hence
// don't affect trait selection or auto
// traits, and they are erased during
// trans.
gcx.types.re_empty
},
}
});
debug!(
"infer_anon_definition_from_instantiation: definition_ty={:?}",
definition_ty
);
definition_ty
}
}
struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> {

View file

@ -15,12 +15,11 @@
use check::FnCtxt;
use rustc::hir;
use rustc::hir::def_id::{DefId, DefIndex};
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::infer::{InferCtxt};
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc::infer::InferCtxt;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::fold::{TypeFolder, TypeFoldable};
use rustc::ty::subst::{Kind, Substs};
use rustc::util::nodemap::{DefIdSet, FxHashMap};
use rustc::ty::fold::{TypeFoldable, TypeFolder};
use rustc::util::nodemap::DefIdSet;
use syntax::ast;
use syntax_pos::Span;
use std::mem;
@ -30,8 +29,7 @@ use std::rc::Rc;
// Entry point
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body)
-> &'gcx ty::TypeckTables<'gcx> {
pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body) -> &'gcx ty::TypeckTables<'gcx> {
let item_id = self.tcx.hir.body_owner(body.id());
let item_def_id = self.tcx.hir.local_def_id(item_id);
@ -48,14 +46,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
wbcx.visit_cast_types();
wbcx.visit_free_region_map();
let used_trait_imports = mem::replace(&mut self.tables.borrow_mut().used_trait_imports,
Rc::new(DefIdSet()));
debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
let used_trait_imports = mem::replace(
&mut self.tables.borrow_mut().used_trait_imports,
Rc::new(DefIdSet()),
);
debug!(
"used_trait_imports({:?}) = {:?}",
item_def_id,
used_trait_imports
);
wbcx.tables.used_trait_imports = used_trait_imports;
wbcx.tables.tainted_by_errors = self.is_tainted_by_errors();
debug!("writeback: tables for {:?} are {:#?}", item_def_id, wbcx.tables);
debug!(
"writeback: tables for {:?} are {:#?}",
item_def_id,
wbcx.tables
);
self.tcx.alloc_tables(wbcx.tables)
}
@ -69,7 +77,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// there, it applies a few ad-hoc checks that were not convenient to
// do elsewhere.
struct WritebackCx<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
struct WritebackCx<'cx, 'gcx: 'cx + 'tcx, 'tcx: 'cx> {
fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>,
tables: ty::TypeckTables<'gcx>,
@ -78,9 +86,10 @@ struct WritebackCx<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
}
impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>, body: &'gcx hir::Body)
-> WritebackCx<'cx, 'gcx, 'tcx>
{
fn new(
fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>,
body: &'gcx hir::Body,
) -> WritebackCx<'cx, 'gcx, 'tcx> {
let owner = fcx.tcx.hir.definitions().node_to_hir_id(body.id().node_id);
WritebackCx {
@ -95,7 +104,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
}
fn write_ty_to_tables(&mut self, hir_id: hir::HirId, ty: Ty<'gcx>) {
debug!("write_ty_to_tables({:?}, {:?})", hir_id, ty);
debug!("write_ty_to_tables({:?}, {:?})", hir_id, ty);
assert!(!ty.needs_infer());
self.tables.node_types_mut().insert(hir_id, ty);
}
@ -106,8 +115,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
// operating on scalars, we clear the overload.
fn fix_scalar_builtin_expr(&mut self, e: &hir::Expr) {
match e.node {
hir::ExprUnary(hir::UnNeg, ref inner) |
hir::ExprUnary(hir::UnNot, ref inner) => {
hir::ExprUnary(hir::UnNeg, ref inner) | hir::ExprUnary(hir::UnNot, ref inner) => {
let inner_ty = self.fcx.node_ty(inner.hir_id);
let inner_ty = self.fcx.resolve_type_vars_if_possible(&inner_ty);
@ -117,8 +125,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
tables.node_substs_mut().remove(e.hir_id);
}
}
hir::ExprBinary(ref op, ref lhs, ref rhs) |
hir::ExprAssignOp(ref op, ref lhs, ref rhs) => {
hir::ExprBinary(ref op, ref lhs, ref rhs)
| hir::ExprAssignOp(ref op, ref lhs, ref rhs) => {
let lhs_ty = self.fcx.node_ty(lhs.hir_id);
let lhs_ty = self.fcx.resolve_type_vars_if_possible(&lhs_ty);
@ -137,15 +145,18 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
adjustments.get_mut(lhs.hir_id).map(|a| a.pop());
adjustments.get_mut(rhs.hir_id).map(|a| a.pop());
}
},
}
hir::ExprAssignOp(..) => {
tables.adjustments_mut().get_mut(lhs.hir_id).map(|a| a.pop());
},
_ => {},
tables
.adjustments_mut()
.get_mut(lhs.hir_id)
.map(|a| a.pop());
}
_ => {}
}
}
}
_ => {},
_ => {}
}
}
}
@ -189,11 +200,11 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
match p.node {
hir::PatKind::Binding(..) => {
let bm = *self.fcx
.tables
.borrow()
.pat_binding_modes()
.get(p.hir_id)
.expect("missing binding mode");
.tables
.borrow()
.pat_binding_modes()
.get(p.hir_id)
.expect("missing binding mode");
self.tables.pat_binding_modes_mut().insert(p.hir_id, bm);
}
_ => {}
@ -228,14 +239,20 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
ty::UpvarCapture::ByRef(ref upvar_borrow) => {
let r = upvar_borrow.region;
let r = self.resolve(&r, &upvar_id.var_id);
ty::UpvarCapture::ByRef(
ty::UpvarBorrow { kind: upvar_borrow.kind, region: r })
ty::UpvarCapture::ByRef(ty::UpvarBorrow {
kind: upvar_borrow.kind,
region: r,
})
}
};
debug!("Upvar capture for {:?} resolved to {:?}",
upvar_id,
new_upvar_capture);
self.tables.upvar_capture_map.insert(*upvar_id, new_upvar_capture);
debug!(
"Upvar capture for {:?} resolved to {:?}",
upvar_id,
new_upvar_capture
);
self.tables
.upvar_capture_map
.insert(*upvar_id, new_upvar_capture);
}
}
@ -249,7 +266,9 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
owner: common_local_id_root.index,
local_id: id,
};
self.tables.closure_kind_origins_mut().insert(hir_id, origin);
self.tables
.closure_kind_origins_mut()
.insert(hir_id, origin);
}
}
@ -270,7 +289,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
}
fn visit_free_region_map(&mut self) {
let free_region_map = self.tcx().lift_to_global(&self.fcx.tables.borrow().free_region_map);
let free_region_map = self.tcx()
.lift_to_global(&self.fcx.tables.borrow().free_region_map);
let free_region_map = free_region_map.expect("all regions in free-region-map are global");
self.tables.free_region_map = free_region_map;
}
@ -279,77 +299,25 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
let gcx = self.tcx().global_tcx();
for (&def_id, anon_defn) in self.fcx.anon_types.borrow().iter() {
let node_id = gcx.hir.as_local_node_id(def_id).unwrap();
let inside_ty = self.resolve(&anon_defn.concrete_ty, &node_id);
// Use substs to build up a reverse map from regions
// to their identity mappings.
// This is necessary because of `impl Trait` lifetimes
// are computed by replacing existing lifetimes with 'static
// and remapping only those used in the `impl Trait` return type,
// resulting in the parameters shifting.
let id_substs = Substs::identity_for_item(gcx, def_id);
let map: FxHashMap<Kind<'tcx>, Kind<'gcx>> =
anon_defn.substs
.iter()
.enumerate()
.map(|(index, subst)| (*subst, id_substs[index]))
.collect();
// Convert the type from the function into a type valid outside
// the function, by replacing invalid regions with 'static,
// after producing an error for each of them.
let outside_ty = gcx.fold_regions(&inside_ty, &mut false, |r, _| {
match *r {
// 'static and early-bound regions are valid.
ty::ReStatic |
ty::ReEmpty => r,
// All other regions, we map them appropriately to their adjusted
// indices, erroring if we find any lifetimes that were not mapped
// into the new set.
_ => if let Some(r1) =
map.get(&Kind::from(r)).and_then(|k| k.as_region()) { r1 } else
{
// No mapping was found. This means that
// it is either a disallowed lifetime,
// which will be caught by regionck, or it
// is a region in a non-upvar closure
// generic, which is explicitly
// allowed. If that surprises you, read
// on.
//
// The case of closure is a somewhat
// subtle (read: hacky) consideration. The
// problem is that our closure types
// currently include all the lifetime
// parameters declared on the enclosing
// function, even if they are unused by
// the closure itself. We can't readily
// filter them out, so here we replace
// those values with `'empty`. This can't
// really make a difference to the rest of
// the compiler; those regions are ignored
// for the outlives relation, and hence
// don't affect trait selection or auto
// traits, and they are erased during
// trans.
gcx.types.re_empty
},
}
});
let instantiated_ty = self.resolve(&anon_defn.concrete_ty, &node_id);
let definition_ty = self.fcx.infer_anon_definition_from_instantiation(
def_id,
anon_defn,
instantiated_ty,
);
let hir_id = self.tcx().hir.node_to_hir_id(node_id);
self.tables.node_types_mut().insert(hir_id, outside_ty);
self.tables.node_types_mut().insert(hir_id, definition_ty);
}
}
fn visit_node_id(&mut self, span: Span, hir_id: hir::HirId) {
// Export associated path extensions and method resultions.
if let Some(def) = self.fcx
.tables
.borrow_mut()
.type_dependent_defs_mut()
.remove(hir_id) {
.tables
.borrow_mut()
.type_dependent_defs_mut()
.remove(hir_id)
{
self.tables.type_dependent_defs_mut().insert(hir_id, def);
}
@ -373,10 +341,10 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
fn visit_adjustments(&mut self, span: Span, hir_id: hir::HirId) {
let adjustment = self.fcx
.tables
.borrow_mut()
.adjustments_mut()
.remove(hir_id);
.tables
.borrow_mut()
.adjustments_mut()
.remove(hir_id);
match adjustment {
None => {
debug!("No adjustments for node {:?}", hir_id);
@ -384,18 +352,24 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
Some(adjustment) => {
let resolved_adjustment = self.resolve(&adjustment, &span);
debug!("Adjustments for node {:?}: {:?}", hir_id, resolved_adjustment);
self.tables.adjustments_mut().insert(hir_id, resolved_adjustment);
debug!(
"Adjustments for node {:?}: {:?}",
hir_id,
resolved_adjustment
);
self.tables
.adjustments_mut()
.insert(hir_id, resolved_adjustment);
}
}
}
fn visit_pat_adjustments(&mut self, span: Span, hir_id: hir::HirId) {
let adjustment = self.fcx
.tables
.borrow_mut()
.pat_adjustments_mut()
.remove(hir_id);
.tables
.borrow_mut()
.pat_adjustments_mut()
.remove(hir_id);
match adjustment {
None => {
debug!("No pat_adjustments for node {:?}", hir_id);
@ -403,8 +377,14 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
Some(adjustment) => {
let resolved_adjustment = self.resolve(&adjustment, &span);
debug!("pat_adjustments for node {:?}: {:?}", hir_id, resolved_adjustment);
self.tables.pat_adjustments_mut().insert(hir_id, resolved_adjustment);
debug!(
"pat_adjustments for node {:?}: {:?}",
hir_id,
resolved_adjustment
);
self.tables
.pat_adjustments_mut()
.insert(hir_id, resolved_adjustment);
}
}
}
@ -420,7 +400,9 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
local_id,
};
let fn_sig = self.resolve(fn_sig, &hir_id);
self.tables.liberated_fn_sigs_mut().insert(hir_id, fn_sig.clone());
self.tables
.liberated_fn_sigs_mut()
.insert(hir_id, fn_sig.clone());
}
}
@ -440,15 +422,18 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
}
fn resolve<T>(&self, x: &T, span: &Locatable) -> T::Lifted
where T: TypeFoldable<'tcx> + ty::Lift<'gcx>
where
T: TypeFoldable<'tcx> + ty::Lift<'gcx>,
{
let x = x.fold_with(&mut Resolver::new(self.fcx, span, self.body));
if let Some(lifted) = self.tcx().lift_to_global(&x) {
lifted
} else {
span_bug!(span.to_span(&self.fcx.tcx),
"writeback: `{:?}` missing from the global type context",
x);
span_bug!(
span.to_span(&self.fcx.tcx),
"writeback: `{:?}` missing from the global type context",
x
);
}
}
}
@ -458,11 +443,15 @@ trait Locatable {
}
impl Locatable for Span {
fn to_span(&self, _: &TyCtxt) -> Span { *self }
fn to_span(&self, _: &TyCtxt) -> Span {
*self
}
}
impl Locatable for ast::NodeId {
fn to_span(&self, tcx: &TyCtxt) -> Span { tcx.hir.span(*self) }
fn to_span(&self, tcx: &TyCtxt) -> Span {
tcx.hir.span(*self)
}
}
impl Locatable for DefIndex {
@ -483,7 +472,7 @@ impl Locatable for hir::HirId {
// The Resolver. This is the type folding engine that detects
// unresolved types and so forth.
struct Resolver<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
struct Resolver<'cx, 'gcx: 'cx + 'tcx, 'tcx: 'cx> {
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
span: &'cx Locatable,
@ -491,9 +480,11 @@ struct Resolver<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
}
impl<'cx, 'gcx, 'tcx> Resolver<'cx, 'gcx, 'tcx> {
fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>, span: &'cx Locatable, body: &'gcx hir::Body)
-> Resolver<'cx, 'gcx, 'tcx>
{
fn new(
fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>,
span: &'cx Locatable,
body: &'gcx hir::Body,
) -> Resolver<'cx, 'gcx, 'tcx> {
Resolver {
tcx: fcx.tcx,
infcx: fcx,
@ -504,7 +495,8 @@ impl<'cx, 'gcx, 'tcx> Resolver<'cx, 'gcx, 'tcx> {
fn report_error(&self, t: Ty<'tcx>) {
if !self.tcx.sess.has_errors() {
self.infcx.need_type_info(Some(self.body.id()), self.span.to_span(&self.tcx), t);
self.infcx
.need_type_info(Some(self.body.id()), self.span.to_span(&self.tcx), t);
}
}
}
@ -518,8 +510,10 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Resolver<'cx, 'gcx, 'tcx> {
match self.infcx.fully_resolve(&t) {
Ok(t) => t,
Err(_) => {
debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable",
t);
debug!(
"Resolver::fold_ty: input type `{:?}` not fully resolvable",
t
);
self.report_error(t);
self.tcx().types.err
}
@ -531,9 +525,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Resolver<'cx, 'gcx, 'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match self.infcx.fully_resolve(&r) {
Ok(r) => r,
Err(_) => {
self.tcx.types.re_static
}
Err(_) => self.tcx.types.re_static,
}
}
}