about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/borrow_check/nll/mod.rs4
-rw-r--r--src/librustc_mir/borrow_check/nll/renumber.rs68
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs49
-rw-r--r--src/librustc_mir/borrow_check/nll/universal_regions.rs6
-rw-r--r--src/test/mir-opt/nll/named-lifetimes-basic.rs6
-rw-r--r--src/test/ui/nll/projection-return.rs29
6 files changed, 94 insertions, 68 deletions
diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs
index 23fa2689053..6977d91d25a 100644
--- a/src/librustc_mir/borrow_check/nll/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/mod.rs
@@ -53,7 +53,7 @@ pub(in borrow_check) fn replace_regions_in_mir<'cx, 'gcx, 'tcx>(
     let universal_regions = UniversalRegions::new(infcx, def_id, param_env);
 
     // Replace all remaining regions with fresh inference variables.
-    renumber::renumber_mir(infcx, &universal_regions, mir);
+    renumber::renumber_mir(infcx, mir);
 
     let source = MirSource::item(def_id);
     mir_util::dump_mir(infcx.tcx, None, "renumber", &0, source, mir, |_, _| Ok(()));
@@ -86,6 +86,8 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
         param_env,
         mir,
         fr_fn_body,
+        universal_regions.input_tys,
+        universal_regions.output_ty,
         &liveness,
         flow_inits,
         move_data,
diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs
index 1262c238a13..79505405692 100644
--- a/src/librustc_mir/borrow_check/nll/renumber.rs
+++ b/src/librustc_mir/borrow_check/nll/renumber.rs
@@ -8,50 +8,24 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc_data_structures::indexed_vec::Idx;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, ClosureSubsts, Ty, TypeFoldable};
-use rustc::mir::{BasicBlock, Local, Location, Mir, Statement, StatementKind};
-use rustc::mir::RETURN_PLACE;
+use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind};
 use rustc::mir::visit::{MutVisitor, TyContext};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
 
-use super::ToRegionVid;
-use super::universal_regions::UniversalRegions;
-
 /// 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>,
-    universal_regions: &UniversalRegions<'tcx>,
-    mir: &mut Mir<'tcx>,
-) {
+pub fn renumber_mir<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, mir: &mut Mir<'tcx>) {
     debug!("renumber_mir()");
     debug!("renumber_mir: mir.arg_count={:?}", mir.arg_count);
 
-    // Update the return type and types of the arguments based on the
-    // `universal_regions` computation.
-    debug!("renumber_mir: output_ty={:?}", universal_regions.output_ty);
-    mir.local_decls[RETURN_PLACE].ty = universal_regions.output_ty;
-    for (&input_ty, local) in universal_regions
-        .input_tys
-        .iter()
-        .zip((1..).map(Local::new))
-    {
-        debug!("renumber_mir: input_ty={:?} local={:?}", input_ty, local);
-        mir.local_decls[local].ty = input_ty;
-    }
-
-    let mut visitor = NLLVisitor {
-        infcx,
-        arg_count: mir.arg_count,
-    };
+    let mut visitor = NLLVisitor { infcx };
     visitor.visit_mir(mir);
 }
 
 struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-    arg_count: usize,
 }
 
 impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
@@ -71,45 +45,13 @@ impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
                 self.infcx.next_nll_region_var(origin)
             })
     }
-
-    /// Checks that all the regions appearing in `value` have already
-    /// been renumbered. `FreeRegions` code should have done this.
-    fn assert_free_regions_are_renumbered<T>(&self, value: &T)
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        debug!("assert_free_regions_are_renumbered(value={:?})", value);
-
-        self.infcx.tcx.for_each_free_region(value, |region| {
-            region.to_region_vid(); // will panic if `region` is not renumbered
-        });
-    }
-
-    fn is_argument_or_return_slot(&self, local: Local) -> bool {
-        // The first argument is return slot, next N are arguments.
-        local.index() <= self.arg_count
-    }
 }
 
 impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
     fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
-        let is_arg = match ty_context {
-            TyContext::LocalDecl { local, .. } => self.is_argument_or_return_slot(local),
-            TyContext::ReturnTy(..) => true,
-            TyContext::Location(..) => false,
-        };
-        debug!(
-            "visit_ty(ty={:?}, is_arg={:?}, ty_context={:?})",
-            ty,
-            is_arg,
-            ty_context
-        );
+        debug!("visit_ty(ty={:?}, ty_context={:?})", ty, ty_context);
 
-        if is_arg {
-            self.assert_free_regions_are_renumbered(ty);
-        } else {
-            *ty = self.renumber_regions(ty_context, ty);
-        }
+        *ty = self.renumber_regions(ty_context, ty);
 
         debug!("visit_ty: ty={:?}", ty);
     }
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 5c3cdbe2207..6cdd77048c9 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -46,12 +46,31 @@ mod liveness;
 /// This phase of type-check ought to be infallible -- this is because
 /// the original, HIR-based type-check succeeded. So if any errors
 /// occur here, we will get a `bug!` reported.
+///
+/// # 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
+/// - `implicit_region_bound` -- a region which all generic parameters are assumed
+///   to outlive; should represent the fn body
+/// - `input_tys` -- fully liberated, but **not** normalized, expected types of the arguments;
+///   the types of the input parameters found in the MIR itself will be equated with these
+/// - `output_ty` -- fully liberaetd, but **not** normalized, expected return type;
+///   the type for the RETURN_PLACE will be equated with this
+/// - `liveness` -- results of a liveness computation on the MIR; used to create liveness
+///   constraints for the regions in the types of variables
+/// - `flow_inits` -- results of a maybe-init dataflow analysis
+/// - `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>,
     implicit_region_bound: ty::Region<'tcx>,
+    input_tys: &[Ty<'tcx>],
+    output_ty: Ty<'tcx>,
     liveness: &LivenessResults,
     flow_inits: &mut FlowAtLocation<MaybeInitializedLvals<'_, 'gcx, 'tcx>>,
     move_data: &MoveData<'tcx>,
@@ -62,7 +81,16 @@ pub(crate) fn type_check<'gcx, 'tcx>(
         param_env,
         mir,
         Some(implicit_region_bound),
-        &mut |cx| liveness::generate(cx, mir, liveness, flow_inits, move_data),
+        &mut |cx| {
+            liveness::generate(cx, mir, liveness, flow_inits, move_data);
+
+            // Equate the input and output tys given by the user with
+            // the ones found in the MIR.
+            cx.equate_input_or_output(output_ty, mir.local_decls[RETURN_PLACE].ty);
+            for (&input_ty, local) in input_tys.iter().zip((1..).map(Local::new)) {
+                cx.equate_input_or_output(input_ty, mir.local_decls[local].ty);
+            }
+        },
     )
 }
 
@@ -666,6 +694,25 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         })
     }
 
+    fn equate_input_or_output(&mut self, unnormalized_a: Ty<'tcx>, b: Ty<'tcx>) {
+        let start_position = Location {
+            block: START_BLOCK,
+            statement_index: 0,
+        };
+        let a = self.normalize(&unnormalized_a, start_position);
+        if let Err(terr) = self.eq_types(a, b, start_position.at_self()) {
+            span_mirbug!(
+                self,
+                start_position,
+                "bad input or output {:?} normalized to {:?} should equal {:?} but got error {:?}",
+                unnormalized_a,
+                a,
+                b,
+                terr
+            );
+        }
+    }
+
     fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
         self.infcx.tcx
     }
diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs
index 5f4a72542b2..99beae13bd9 100644
--- a/src/librustc_mir/borrow_check/nll/universal_regions.rs
+++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs
@@ -69,12 +69,14 @@ pub struct UniversalRegions<'tcx> {
     /// closure type, but for a top-level function it's the `TyFnDef`.
     pub defining_ty: Ty<'tcx>,
 
-    /// The return type of this function, with all regions replaced
-    /// by their universal `RegionVid` equivalents.
+    /// The return type of this function, with all regions replaced by
+    /// their universal `RegionVid` equivalents. This type is **NOT
+    /// NORMALIZED**.
     pub output_ty: Ty<'tcx>,
 
     /// The fully liberated input types of this function, with all
     /// regions replaced by their universal `RegionVid` equivalents.
+    /// This type is **NOT NORMALIZED**.
     pub input_tys: &'tcx [Ty<'tcx>],
 
     /// Each RBP `('a, GK)` indicates that `GK: 'a` can be assumed to
diff --git a/src/test/mir-opt/nll/named-lifetimes-basic.rs b/src/test/mir-opt/nll/named-lifetimes-basic.rs
index 71304f71b61..f14979f9733 100644
--- a/src/test/mir-opt/nll/named-lifetimes-basic.rs
+++ b/src/test/mir-opt/nll/named-lifetimes-basic.rs
@@ -39,7 +39,11 @@ fn main() {
 // | '_#2r    | {'_#2r, bb0[0], bb0[1]}
 // | '_#3r    | {'_#3r, bb0[0], bb0[1]}
 // | '_#4r    | {'_#4r, bb0[0], bb0[1]}
+// | '_#5r    | {'_#1r, bb0[0], bb0[1]}
+// | '_#6r    | {'_#2r, bb0[0], bb0[1]}
+// | '_#7r    | {'_#1r, bb0[0], bb0[1]}
+// | '_#8r    | {'_#3r, bb0[0], bb0[1]}
 // |
 // ...
-// fn use_x(_1: &'_#1r mut i32, _2: &'_#2r u32, _3: &'_#1r u32, _4: &'_#3r u32) -> bool {
+// fn use_x(_1: &'_#5r mut i32, _2: &'_#6r u32, _3: &'_#7r u32, _4: &'_#8r u32) -> bool {
 // END rustc.use_x.nll.0.mir
diff --git a/src/test/ui/nll/projection-return.rs b/src/test/ui/nll/projection-return.rs
new file mode 100644
index 00000000000..31388cf50c5
--- /dev/null
+++ b/src/test/ui/nll/projection-return.rs
@@ -0,0 +1,29 @@
+// 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
+// must-compile-successfully
+
+#![feature(rustc_attrs)]
+
+trait Foo {
+    type Bar;
+}
+
+impl Foo for () {
+    type Bar = u32;
+}
+
+fn foo() -> <() as Foo>::Bar {
+    22
+}
+
+fn main() { }
+