diff --git a/src/librustc/infer/anon_types/mod.rs b/src/librustc/infer/anon_types/mod.rs index 74daeb837c92..f163076218a8 100644 --- a/src/librustc/infer/anon_types/mod.rs +++ b/src/librustc/infer/anon_types/mod.rs @@ -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>; @@ -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<'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> { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 1052f031bbf1..29dc983ab560 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -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<'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(&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, } } }