diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index fe46f37f661c9..4b78564476d29 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -91,9 +91,10 @@ use middle::region; use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::traits; -use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::{self, Binder, Region, Ty, TyCtxt, TypeFoldable}; use rustc::infer::{self, GenericKind, SubregionOrigin, VerifyBound}; use rustc::ty::adjustment; +use rustc::ty::fold::TypeVisitor; use rustc::ty::outlives::Component; use rustc::ty::wf; @@ -530,10 +531,57 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let least_region = least_region.unwrap_or(self.tcx.types.re_static); debug!("constrain_anon_types: least_region={:?}", least_region); + struct RegionExceptClosureNonUpvarVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a, F> { + tcx: TyCtxt<'a, 'gcx, 'tcx>, + current_depth: u32, + f: F, + } + + impl<'a, 'gcx, 'tcx, F> TypeVisitor<'tcx> for + RegionExceptClosureNonUpvarVisitor<'a, 'gcx, 'tcx, F> + where F: FnMut(ty::Region<'tcx>) + { + fn visit_binder>(&mut self, t: &Binder) -> bool { + self.current_depth += 1; + t.skip_binder().visit_with(self); + self.current_depth -= 1; + + false // keep visiting + } + + // Skip the non-upvar generics in closures-- we don't want to place bounds on those + // because the closure can outlive them. + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + if let ty::TypeVariants::TyClosure(def_id, ref closure_substs) = t.sty { + // Only iterate over the upvar tys, skipping others + for subst in closure_substs.upvar_tys(def_id, self.tcx) { + subst.visit_with(self); + } + false // keep visiting + } else { + t.super_visit_with(self) + } + } + + fn visit_region(&mut self, r: Region<'tcx>) -> bool { + match *r { + ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => { + // ignore bound regions + } + _ => (self.f)(r), + } + + false // keep visiting + } + } + // Require that all regions outlive `least_region` - self.tcx.for_each_free_region(&concrete_ty, |region| { - self.sub_regions(infer::CallReturn(span), least_region, region); - }); + let mut visitor = RegionExceptClosureNonUpvarVisitor { + tcx: self.tcx, + current_depth: 0, + f: |region| self.sub_regions(infer::CallReturn(span), least_region, region), + }; + concrete_ty.visit_with(&mut visitor); } } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 710df2ab140a9..bbc3394da933d 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -18,7 +18,7 @@ use rustc::hir::def_id::{DefId, DefIndex}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::infer::{InferCtxt}; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::fold::{TypeFolder,TypeFoldable}; +use rustc::ty::fold::{TypeFolder, TypeFoldable}; use rustc::ty::subst::{Kind, Substs}; use rustc::util::nodemap::{DefIdSet, FxHashMap}; use syntax::ast; @@ -297,7 +297,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { // 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 = + let map: FxHashMap, Kind<'gcx>> = anon_defn.substs .iter() .enumerate() @@ -319,12 +319,10 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { _ => if let Some(r1) = map.get(&Kind::from(r)).and_then(|k| k.as_region()) { r1 } else { - let span = node_id.to_span(&self.fcx.tcx); - self.tcx().sess.delay_span_bug( - span, - &format!("only named lifetimes are allowed in `impl Trait`, \ - but `{}` was found in the type `{}`", - r, inside_ty)); + // 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. gcx.types.re_static }, }