about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2017-12-10 10:23:45 -0500
committerNiko Matsakis <niko@alum.mit.edu>2017-12-20 14:04:52 -0500
commit93afb1affc9f4e7616e05a3fc2fdb66e81f35d1e (patch)
tree2c2364727393a6c76b90666c4aa7c2051871dea0 /src
parentda63aaa7ab71ad5ba75340f3719591f370b847e2 (diff)
downloadrust-93afb1affc9f4e7616e05a3fc2fdb66e81f35d1e.tar.gz
rust-93afb1affc9f4e7616e05a3fc2fdb66e81f35d1e.zip
connect NLL type checker to the impl trait code
We now add the suitable `impl Trait` constraints.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/infer/anon_types/mod.rs47
-rw-r--r--src/librustc/util/ppaux.rs18
-rw-r--r--src/librustc_mir/borrow_check/nll/mod.rs3
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/mod.rs4
-rw-r--r--src/librustc_mir/borrow_check/nll/renumber.rs34
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/input_output.rs109
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs8
-rw-r--r--src/librustc_mir/borrow_check/nll/universal_regions.rs17
-rw-r--r--src/librustc_typeck/check/mod.rs16
-rw-r--r--src/test/run-pass/impl-trait/example-calendar.rs3
-rw-r--r--src/test/ui/nll/ty-outlives/impl-trait-captures.rs27
-rw-r--r--src/test/ui/nll/ty-outlives/impl-trait-captures.stderr14
-rw-r--r--src/test/ui/nll/ty-outlives/impl-trait-outlives.rs51
-rw-r--r--src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr26
14 files changed, 339 insertions, 38 deletions
diff --git a/src/librustc/infer/anon_types/mod.rs b/src/librustc/infer/anon_types/mod.rs
index f163076218a..a3d236ac1b6 100644
--- a/src/librustc/infer/anon_types/mod.rs
+++ b/src/librustc/infer/anon_types/mod.rs
@@ -93,20 +93,34 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// Moreover, it returns a `AnonTypeMap` that would map `?0` to
     /// info about the `impl Iterator<..>` type and `?1` to info about
     /// the `impl Debug` type.
+    ///
+    /// # Parameters
+    ///
+    /// - `parent_def_id` -- we will only instantiate anonymous types
+    ///   with this parent. This is typically the def-id of the function
+    ///   in whose return type anon types are being instantiated.
+    /// - `body_id` -- the body-id with which the resulting obligations should
+    ///   be associated
+    /// - `param_env` -- the in-scope parameter environment to be used for
+    ///   obligations
+    /// - `value` -- the value within which we are instantiating anon types
     pub fn instantiate_anon_types<T: TypeFoldable<'tcx>>(
         &self,
+        parent_def_id: DefId,
         body_id: ast::NodeId,
         param_env: ty::ParamEnv<'tcx>,
         value: &T,
     ) -> InferOk<'tcx, (T, AnonTypeMap<'tcx>)> {
         debug!(
-            "instantiate_anon_types(value={:?}, body_id={:?}, param_env={:?})",
+            "instantiate_anon_types(value={:?}, parent_def_id={:?}, body_id={:?}, param_env={:?})",
             value,
+            parent_def_id,
             body_id,
             param_env,
         );
         let mut instantiator = Instantiator {
             infcx: self,
+            parent_def_id,
             body_id,
             param_env,
             anon_types: DefIdMap(),
@@ -480,6 +494,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
 struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> {
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+    parent_def_id: DefId,
     body_id: ast::NodeId,
     param_env: ty::ParamEnv<'tcx>,
     anon_types: AnonTypeMap<'tcx>,
@@ -489,11 +504,33 @@ struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> {
 impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
     fn instantiate_anon_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: &T) -> T {
         debug!("instantiate_anon_types_in_map(value={:?})", value);
+        let tcx = self.infcx.tcx;
         value.fold_with(&mut BottomUpFolder {
-            tcx: self.infcx.tcx,
-            fldop: |ty| if let ty::TyAnon(def_id, substs) = ty.sty {
-                self.fold_anon_ty(ty, def_id, substs)
-            } else {
+            tcx,
+            fldop: |ty| {
+                if let ty::TyAnon(def_id, substs) = ty.sty {
+                    // Check that this is `impl Trait` type is declared by
+                    // `parent_def_id`. During the first phase of type-check, this
+                    // is true, but during NLL type-check, we sometimes encounter
+                    // `impl Trait` types in e.g. inferred closure signatures that
+                    // are not 'local' to the current function and hence which
+                    // ought not to be instantiated.
+                    if let Some(anon_node_id) = tcx.hir.as_local_node_id(def_id) {
+                        let anon_parent_node_id = tcx.hir.get_parent(anon_node_id);
+                        let anon_parent_def_id = tcx.hir.local_def_id(anon_parent_node_id);
+                        if self.parent_def_id == anon_parent_def_id {
+                            return self.fold_anon_ty(ty, def_id, substs);
+                        }
+
+                        debug!("instantiate_anon_types_in_map: \
+                                encountered anon with wrong parent \
+                                def_id={:?} \
+                                anon_parent_def_id={:?}",
+                               def_id,
+                               anon_parent_def_id);
+                    }
+                }
+
                 ty
             },
         })
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 5bfa6464568..51841836698 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -865,13 +865,17 @@ impl fmt::Debug for ty::RegionVid {
 define_print! {
     () ty::InferTy, (self, f, cx) {
         display {
-            match *self {
-                ty::TyVar(_) => write!(f, "_"),
-                ty::IntVar(_) => write!(f, "{}", "{integer}"),
-                ty::FloatVar(_) => write!(f, "{}", "{float}"),
-                ty::FreshTy(v) => write!(f, "FreshTy({})", v),
-                ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
-                ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v)
+            if cx.is_verbose {
+                print!(f, cx, print_debug(self))
+            } else {
+                match *self {
+                    ty::TyVar(_) => write!(f, "_"),
+                    ty::IntVar(_) => write!(f, "{}", "{integer}"),
+                    ty::FloatVar(_) => write!(f, "{}", "{float}"),
+                    ty::FreshTy(v) => write!(f, "FreshTy({})", v),
+                    ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
+                    ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v)
+                }
             }
         }
         debug {
diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs
index 7acbe2ebf93..98a74f06703 100644
--- a/src/librustc_mir/borrow_check/nll/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/mod.rs
@@ -77,13 +77,12 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
     Option<ClosureRegionRequirements<'gcx>>,
 ) {
     // Run the MIR type-checker.
-    let mir_node_id = infcx.tcx.hir.as_local_node_id(def_id).unwrap();
     let liveness = &LivenessResults::compute(mir);
     let constraint_sets = &type_check::type_check(
         infcx,
-        mir_node_id,
         param_env,
         mir,
+        def_id,
         &universal_regions,
         &liveness,
         flow_inits,
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index 9f7219b1f55..6f3e6cb1ec5 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -246,13 +246,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             .map(|origin| RegionDefinition::new(origin))
             .collect();
 
+        let nll_dump_cause = ty::tls::with(|tcx| tcx.sess.opts.debugging_opts.nll_dump_cause);
+
         let mut result = Self {
             definitions,
             elements: elements.clone(),
             liveness_constraints: RegionValues::new(
                 elements,
                 num_region_variables,
-                TrackCauses(true),
+                TrackCauses(nll_dump_cause),
             ),
             inferred_values: None,
             constraints: Vec::new(),
diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs
index 79505405692..4aee48b979d 100644
--- a/src/librustc_mir/borrow_check/nll/renumber.rs
+++ b/src/librustc_mir/borrow_check/nll/renumber.rs
@@ -16,7 +16,7 @@ use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
 
 /// Replaces all free regions appearing in the MIR with fresh
 /// inference variables, returning the number of variables created.
-pub fn renumber_mir<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, mir: &mut Mir<'tcx>) {
+pub fn renumber_mir<'tcx>(infcx: &InferCtxt<'_, '_, 'tcx>, mir: &mut Mir<'tcx>) {
     debug!("renumber_mir()");
     debug!("renumber_mir: mir.arg_count={:?}", mir.arg_count);
 
@@ -24,26 +24,36 @@ pub fn renumber_mir<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, mir: &mut
     visitor.visit_mir(mir);
 }
 
+/// Replaces all regions appearing in `value` with fresh inference
+/// variables.
+pub fn renumber_regions<'tcx, T>(
+    infcx: &InferCtxt<'_, '_, 'tcx>,
+    ty_context: TyContext,
+    value: &T,
+) -> T
+where
+    T: TypeFoldable<'tcx>,
+{
+    debug!("renumber_regions(value={:?})", value);
+
+    infcx
+        .tcx
+        .fold_regions(value, &mut false, |_region, _depth| {
+            let origin = NLLRegionVariableOrigin::Inferred(ty_context);
+            infcx.next_nll_region_var(origin)
+        })
+}
+
 struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
 }
 
 impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
-    /// Replaces all regions appearing in `value` with fresh inference
-    /// variables. This is what we do for almost the entire MIR, with
-    /// the exception of the declared types of our arguments.
     fn renumber_regions<T>(&mut self, ty_context: TyContext, value: &T) -> T
     where
         T: TypeFoldable<'tcx>,
     {
-        debug!("renumber_regions(value={:?})", value);
-
-        self.infcx
-            .tcx
-            .fold_regions(value, &mut false, |_region, _depth| {
-                let origin = NLLRegionVariableOrigin::Inferred(ty_context);
-                self.infcx.next_nll_region_var(origin)
-            })
+        renumber_regions(self.infcx, ty_context, value)
     }
 }
 
diff --git a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs
index b85573b9c07..4db8e3c793d 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs
@@ -17,9 +17,15 @@
 //! `RETURN_PLACE` the MIR arguments) are always fully normalize (and
 //! contain revealed `impl Trait` values).
 
+use borrow_check::nll::renumber;
 use borrow_check::nll::universal_regions::UniversalRegions;
+use rustc::hir::def_id::DefId;
+use rustc::infer::InferOk;
 use rustc::ty::Ty;
+use rustc::ty::subst::Subst;
 use rustc::mir::*;
+use rustc::mir::visit::TyContext;
+use rustc::traits::PredicateObligations;
 
 use rustc_data_structures::indexed_vec::Idx;
 
@@ -29,13 +35,17 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
     pub(super) fn equate_inputs_and_outputs(
         &mut self,
         mir: &Mir<'tcx>,
+        mir_def_id: DefId,
         universal_regions: &UniversalRegions<'tcx>,
     ) {
+        let tcx = self.infcx.tcx;
+
         let &UniversalRegions {
             unnormalized_output_ty,
             unnormalized_input_tys,
             ..
         } = universal_regions;
+        let infcx = self.infcx;
 
         let start_position = Location {
             block: START_BLOCK,
@@ -52,10 +62,88 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
 
         // Return types are a bit more complex. They may contain existential `impl Trait`
         // types.
-
+        debug!(
+            "equate_inputs_and_outputs: unnormalized_output_ty={:?}",
+            unnormalized_output_ty
+        );
         let output_ty = self.normalize(&unnormalized_output_ty, start_position);
+        debug!(
+            "equate_inputs_and_outputs: normalized output_ty={:?}",
+            output_ty
+        );
         let mir_output_ty = mir.local_decls[RETURN_PLACE].ty;
-        self.equate_normalized_input_or_output(start_position, output_ty, mir_output_ty);
+        let anon_type_map = self.fully_perform_op(start_position.at_self(), |cx| {
+            let mut obligations = ObligationAccumulator::default();
+
+            let (output_ty, anon_type_map) = obligations.add(infcx.instantiate_anon_types(
+                mir_def_id,
+                cx.body_id,
+                cx.param_env,
+                &output_ty,
+            ));
+            debug!(
+                "equate_inputs_and_outputs: instantiated output_ty={:?}",
+                output_ty
+            );
+            debug!(
+                "equate_inputs_and_outputs: anon_type_map={:#?}",
+                anon_type_map
+            );
+
+            debug!(
+                "equate_inputs_and_outputs: mir_output_ty={:?}",
+                mir_output_ty
+            );
+            obligations.add(infcx
+                .at(&cx.misc(cx.last_span), cx.param_env)
+                .eq(output_ty, mir_output_ty)?);
+
+            for (&anon_def_id, anon_decl) in &anon_type_map {
+                let anon_defn_ty = tcx.type_of(anon_def_id);
+                let anon_defn_ty = anon_defn_ty.subst(tcx, anon_decl.substs);
+                let anon_defn_ty = renumber::renumber_regions(
+                    cx.infcx,
+                    TyContext::Location(start_position),
+                    &anon_defn_ty,
+                );
+                debug!(
+                    "equate_inputs_and_outputs: concrete_ty={:?}",
+                    anon_decl.concrete_ty
+                );
+                debug!("equate_inputs_and_outputs: anon_defn_ty={:?}", anon_defn_ty);
+                obligations.add(infcx
+                    .at(&cx.misc(cx.last_span), cx.param_env)
+                    .eq(anon_decl.concrete_ty, anon_defn_ty)?);
+            }
+
+            debug!("equate_inputs_and_outputs: equated");
+
+            Ok(InferOk {
+                value: Some(anon_type_map),
+                obligations: obligations.into_vec(),
+            })
+        }).unwrap_or_else(|terr| {
+                span_mirbug!(
+                    self,
+                    start_position,
+                    "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
+                    output_ty,
+                    mir_output_ty,
+                    terr
+                );
+                None
+            });
+
+        // Finally
+        if let Some(anon_type_map) = anon_type_map {
+            self.fully_perform_op(start_position.at_self(), |_cx| {
+                infcx.constrain_anon_types(&anon_type_map, universal_regions);
+                Ok(InferOk {
+                    value: (),
+                    obligations: vec![],
+                })
+            }).unwrap();
+        }
     }
 
     fn equate_normalized_input_or_output(&mut self, location: Location, a: Ty<'tcx>, b: Ty<'tcx>) {
@@ -73,3 +161,20 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         }
     }
 }
+
+#[derive(Debug, Default)]
+struct ObligationAccumulator<'tcx> {
+    obligations: PredicateObligations<'tcx>,
+}
+
+impl<'tcx> ObligationAccumulator<'tcx> {
+    fn add<T>(&mut self, value: InferOk<'tcx, T>) -> T {
+        let InferOk { value, obligations } = value;
+        self.obligations.extend(obligations);
+        value
+    }
+
+    fn into_vec(self) -> PredicateObligations<'tcx> {
+        self.obligations
+    }
+}
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 48750b62611..4c8a171299f 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -17,6 +17,7 @@ use borrow_check::nll::universal_regions::UniversalRegions;
 use dataflow::FlowAtLocation;
 use dataflow::MaybeInitializedLvals;
 use dataflow::move_paths::MoveData;
+use rustc::hir::def_id::DefId;
 use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
 use rustc::infer::region_constraints::{GenericKind, RegionConstraintData};
 use rustc::traits::{self, FulfillmentContext};
@@ -77,9 +78,9 @@ mod input_output;
 /// # Parameters
 ///
 /// - `infcx` -- inference context to use
-/// - `body_id` -- body-id of the MIR being checked
 /// - `param_env` -- parameter environment to use for trait solving
 /// - `mir` -- MIR to type-check
+/// - `mir_def_id` -- DefId from which the MIR is derived (must be local)
 /// - `region_bound_pairs` -- the implied outlives obligations between type parameters
 ///   and lifetimes (e.g., `&'a T` implies `T: 'a`)
 /// - `implicit_region_bound` -- a region which all generic parameters are assumed
@@ -94,14 +95,15 @@ mod input_output;
 /// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
 pub(crate) fn type_check<'gcx, 'tcx>(
     infcx: &InferCtxt<'_, 'gcx, 'tcx>,
-    body_id: ast::NodeId,
     param_env: ty::ParamEnv<'gcx>,
     mir: &Mir<'tcx>,
+    mir_def_id: DefId,
     universal_regions: &UniversalRegions<'tcx>,
     liveness: &LivenessResults,
     flow_inits: &mut FlowAtLocation<MaybeInitializedLvals<'_, 'gcx, 'tcx>>,
     move_data: &MoveData<'tcx>,
 ) -> MirTypeckRegionConstraints<'tcx> {
+    let body_id = infcx.tcx.hir.as_local_node_id(mir_def_id).unwrap();
     let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
     type_check_internal(
         infcx,
@@ -113,7 +115,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
         &mut |cx| {
             liveness::generate(cx, mir, liveness, flow_inits, move_data);
 
-            cx.equate_inputs_and_outputs(mir, universal_regions);
+            cx.equate_inputs_and_outputs(mir, mir_def_id, universal_regions);
         },
     )
 }
diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs
index 070cea4bef2..6eca1b0a146 100644
--- a/src/librustc_mir/borrow_check/nll/universal_regions.rs
+++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs
@@ -27,6 +27,7 @@ use rustc::hir::def_id::DefId;
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
 use rustc::infer::region_constraints::GenericKind;
 use rustc::infer::outlives::bounds::{self, OutlivesBound};
+use rustc::infer::outlives::free_region_map::FreeRegionRelations;
 use rustc::ty::{self, RegionVid, Ty, TyCtxt};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::Substs;
@@ -484,9 +485,6 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
         let (unnormalized_output_ty, unnormalized_input_tys) =
             inputs_and_output.split_last().unwrap();
 
-        // we should not have created any more variables
-        assert_eq!(self.infcx.num_region_vars(), num_universals);
-
         debug!(
             "build: global regions = {}..{}",
             FIRST_GLOBAL_INDEX,
@@ -793,3 +791,16 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
         })
     }
 }
+
+/// This trait is used by the `impl-trait` constraint code to abstract
+/// over the `FreeRegionMap` from lexical regions and
+/// `UniversalRegions` (from NLL)`.
+impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegions<'tcx> {
+    fn sub_free_regions(&self, shorter: ty::Region<'tcx>, longer: ty::Region<'tcx>) -> bool {
+        let shorter = shorter.to_region_vid();
+        assert!(self.is_universal_region(shorter));
+        let longer = longer.to_region_vid();
+        assert!(self.is_universal_region(longer));
+        self.outlives(longer, shorter)
+    }
+}
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index ef66920604b..14296e78ddd 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -985,7 +985,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
 
     let ret_ty = fn_sig.output();
     fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::SizedReturnType);
-    let ret_ty = fcx.instantiate_anon_types_from_return_value(&ret_ty);
+    let ret_ty = fcx.instantiate_anon_types_from_return_value(fn_id, &ret_ty);
     fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
     fn_sig = fcx.tcx.mk_fn_sig(
         fn_sig.inputs().iter().cloned(),
@@ -1880,11 +1880,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     /// function with type variables and records the `AnonTypeMap` for
     /// later use during writeback. See
     /// `InferCtxt::instantiate_anon_types` for more details.
-    fn instantiate_anon_types_from_return_value<T: TypeFoldable<'tcx>>(&self, value: &T) -> T {
-        debug!("instantiate_anon_types_from_return_value(value={:?})", value);
+    fn instantiate_anon_types_from_return_value<T: TypeFoldable<'tcx>>(
+        &self,
+        fn_id: ast::NodeId,
+        value: &T,
+    ) -> T {
+        let fn_def_id = self.tcx.hir.local_def_id(fn_id);
+        debug!(
+            "instantiate_anon_types_from_return_value(fn_def_id={:?}, value={:?})",
+            fn_def_id,
+            value
+        );
 
         let (value, anon_type_map) = self.register_infer_ok_obligations(
             self.instantiate_anon_types(
+                fn_def_id,
                 self.body_id,
                 self.param_env,
                 value,
diff --git a/src/test/run-pass/impl-trait/example-calendar.rs b/src/test/run-pass/impl-trait/example-calendar.rs
index 0b612c2d3ff..8d035bafab7 100644
--- a/src/test/run-pass/impl-trait/example-calendar.rs
+++ b/src/test/run-pass/impl-trait/example-calendar.rs
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// revisions: normal nll
+//[nll] compile-flags: -Znll -Zborrowck=mir
+
 #![feature(conservative_impl_trait,
            universal_impl_trait,
            fn_traits,
diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.rs b/src/test/ui/nll/ty-outlives/impl-trait-captures.rs
new file mode 100644
index 00000000000..896b74b579b
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.rs
@@ -0,0 +1,27 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags:-Znll -Zborrowck=mir -Zverbose
+
+#![allow(warnings)]
+#![feature(conservative_impl_trait)]
+
+trait Foo<'a> {
+}
+
+impl<'a, T> Foo<'a> for T { }
+
+fn foo<'a, T>(x: &T) -> impl Foo<'a> {
+    x
+        //~^ WARNING not reporting region error due to -Znll
+        //~| ERROR free region `'_#2r` does not outlive free region `ReEarlyBound(0, 'a)`
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
new file mode 100644
index 00000000000..7de994dae88
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
@@ -0,0 +1,14 @@
+warning: not reporting region error due to -Znll
+  --> $DIR/impl-trait-captures.rs:22:5
+   |
+22 |     x
+   |     ^
+
+error: free region `'_#2r` does not outlive free region `ReEarlyBound(0, 'a)`
+  --> $DIR/impl-trait-captures.rs:22:5
+   |
+22 |     x
+   |     ^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/ty-outlives/impl-trait-outlives.rs b/src/test/ui/nll/ty-outlives/impl-trait-outlives.rs
new file mode 100644
index 00000000000..c03ec839808
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/impl-trait-outlives.rs
@@ -0,0 +1,51 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags:-Znll -Zborrowck=mir -Zverbose
+
+#![allow(warnings)]
+#![feature(conservative_impl_trait)]
+
+use std::fmt::Debug;
+
+fn no_region<'a, T>(x: Box<T>) -> impl Debug + 'a
+    //~^ WARNING not reporting region error due to -Znll
+where
+    T: Debug,
+{
+    x
+    //~^ ERROR `T` does not outlive
+}
+
+fn correct_region<'a, T>(x: Box<T>) -> impl Debug + 'a
+where
+    T: 'a + Debug,
+{
+    x
+}
+
+fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
+    //~^ WARNING not reporting region error due to -Znll
+where
+    T: 'b + Debug,
+{
+    x
+    //~^ ERROR `T` does not outlive
+}
+
+fn outlives_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
+where
+    T: 'b + Debug,
+    'b: 'a,
+{
+    x
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr b/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr
new file mode 100644
index 00000000000..4ebd2c7fc43
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr
@@ -0,0 +1,26 @@
+warning: not reporting region error due to -Znll
+  --> $DIR/impl-trait-outlives.rs:18:35
+   |
+18 | fn no_region<'a, T>(x: Box<T>) -> impl Debug + 'a
+   |                                   ^^^^^^^^^^^^^^^
+
+warning: not reporting region error due to -Znll
+  --> $DIR/impl-trait-outlives.rs:34:42
+   |
+34 | fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
+   |                                          ^^^^^^^^^^^^^^^
+
+error: `T` does not outlive `'_#1r`
+  --> $DIR/impl-trait-outlives.rs:23:5
+   |
+23 |     x
+   |     ^
+
+error: `T` does not outlive `'_#1r`
+  --> $DIR/impl-trait-outlives.rs:39:5
+   |
+39 |     x
+   |     ^
+
+error: aborting due to 2 previous errors
+