]> git.lizzy.rs Git - rust.git/commitdiff
propagate `region_bound_pairs` into MIR type-check
authorNiko Matsakis <niko@alum.mit.edu>
Fri, 8 Dec 2017 20:47:36 +0000 (15:47 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Wed, 20 Dec 2017 19:04:51 +0000 (14:04 -0500)
src/librustc_mir/borrow_check/nll/mod.rs
src/librustc_mir/borrow_check/nll/type_check/mod.rs
src/test/ui/nll/ty-outlives/projection-implied-bounds.rs [new file with mode: 0644]
src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr [new file with mode: 0644]
src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.rs [new file with mode: 0644]
src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr [new file with mode: 0644]
src/test/ui/nll/ty-outlives/ty-param-implied-bounds.rs [new file with mode: 0644]
src/test/ui/nll/ty-outlives/ty-param-implied-bounds.stderr [new file with mode: 0644]

index 33a6c9e2d1cbfd5331b3748185429857bcd2e5cc..d18883ce47cbd70dc07ce11a39b74d6ead600804 100644 (file)
@@ -85,6 +85,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
         mir_node_id,
         param_env,
         mir,
+        &universal_regions.region_bound_pairs,
         fr_fn_body,
         universal_regions.input_tys,
         universal_regions.output_ty,
index 32a016e4a0aa4e95e77e7bd0277a0fce34150540..ee455c3e921f1a44bbee891eb20c8cc3982989ff 100644 (file)
@@ -17,7 +17,7 @@
 use dataflow::MaybeInitializedLvals;
 use dataflow::move_paths::MoveData;
 use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
-use rustc::infer::region_constraints::RegionConstraintData;
+use rustc::infer::region_constraints::{GenericKind, RegionConstraintData};
 use rustc::traits::{self, FulfillmentContext};
 use rustc::ty::error::TypeError;
 use rustc::ty::fold::TypeFoldable;
@@ -54,6 +54,8 @@
 /// - `body_id` -- body-id of the MIR being checked
 /// - `param_env` -- parameter environment to use for trait solving
 /// - `mir` -- MIR to type-check
+/// - `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
 ///   to outlive; should represent the fn body
 /// - `input_tys` -- fully liberated, but **not** normalized, expected types of the arguments;
@@ -69,6 +71,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
     body_id: ast::NodeId,
     param_env: ty::ParamEnv<'gcx>,
     mir: &Mir<'tcx>,
+    region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)],
     implicit_region_bound: ty::Region<'tcx>,
     input_tys: &[Ty<'tcx>],
     output_ty: Ty<'tcx>,
@@ -81,6 +84,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
         body_id,
         param_env,
         mir,
+        region_bound_pairs,
         Some(implicit_region_bound),
         &mut |cx| {
             liveness::generate(cx, mir, liveness, flow_inits, move_data);
@@ -100,10 +104,17 @@ fn type_check_internal<'gcx, 'tcx>(
     body_id: ast::NodeId,
     param_env: ty::ParamEnv<'gcx>,
     mir: &Mir<'tcx>,
+    region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)],
     implicit_region_bound: Option<ty::Region<'tcx>>,
     extra: &mut FnMut(&mut TypeChecker<'_, 'gcx, 'tcx>),
 ) -> MirTypeckRegionConstraints<'tcx> {
-    let mut checker = TypeChecker::new(infcx, body_id, param_env, implicit_region_bound);
+    let mut checker = TypeChecker::new(
+        infcx,
+        body_id,
+        param_env,
+        region_bound_pairs,
+        implicit_region_bound,
+    );
     let errors_reported = {
         let mut verifier = TypeVerifier::new(&mut checker, mir);
         verifier.visit_mir(mir);
@@ -571,6 +582,7 @@ struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     param_env: ty::ParamEnv<'gcx>,
     last_span: Span,
     body_id: ast::NodeId,
+    region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
     implicit_region_bound: Option<ty::Region<'tcx>>,
     reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
     constraints: MirTypeckRegionConstraints<'tcx>,
@@ -625,6 +637,7 @@ fn new(
         infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
         body_id: ast::NodeId,
         param_env: ty::ParamEnv<'gcx>,
+        region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
         implicit_region_bound: Option<ty::Region<'tcx>>,
     ) -> Self {
         TypeChecker {
@@ -632,6 +645,7 @@ fn new(
             last_span: DUMMY_SP,
             body_id,
             param_env,
+            region_bound_pairs,
             implicit_region_bound,
             reported_errors: FxHashSet(),
             constraints: MirTypeckRegionConstraints::default(),
@@ -658,7 +672,7 @@ fn fully_perform_op<OP, R>(
         }
 
         self.infcx.process_registered_region_obligations(
-            &[],
+            self.region_bound_pairs,
             self.implicit_region_bound,
             self.param_env,
             self.body_id,
@@ -764,12 +778,12 @@ fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>, location: Loca
                     );
                 };
             }
-            StatementKind::StorageLive(_) |
-            StatementKind::StorageDead(_) |
-            StatementKind::InlineAsm { .. } |
-            StatementKind::EndRegion(_) |
-            StatementKind::Validate(..) |
-            StatementKind::Nop => {}
+            StatementKind::StorageLive(_)
+            | StatementKind::StorageDead(_)
+            | StatementKind::InlineAsm { .. }
+            | StatementKind::EndRegion(_)
+            | StatementKind::Validate(..)
+            StatementKind::Nop => {}
         }
     }
 
@@ -782,13 +796,13 @@ fn check_terminator(
         debug!("check_terminator: {:?}", term);
         let tcx = self.tcx();
         match term.kind {
-            TerminatorKind::Goto { .. } |
-            TerminatorKind::Resume |
-            TerminatorKind::Return |
-            TerminatorKind::GeneratorDrop |
-            TerminatorKind::Unreachable |
-            TerminatorKind::Drop { .. } |
-            TerminatorKind::FalseEdges { .. } => {
+            TerminatorKind::Goto { .. }
+            | TerminatorKind::Resume
+            | TerminatorKind::Return
+            | TerminatorKind::GeneratorDrop
+            | TerminatorKind::Unreachable
+            | TerminatorKind::Drop { .. }
+            TerminatorKind::FalseEdges { .. } => {
                 // no checks needed for these
             }
 
@@ -888,9 +902,11 @@ fn check_terminator(
                 // output) types in the signature must be live, since
                 // all the inputs that fed into it were live.
                 for &late_bound_region in map.values() {
-                    self.constraints
-                        .liveness_set
-                        .push((late_bound_region, term_location, Cause::LiveOther(term_location)));
+                    self.constraints.liveness_set.push((
+                        late_bound_region,
+                        term_location,
+                        Cause::LiveOther(term_location),
+                    ));
                 }
 
                 if self.is_box_free(func) {
@@ -1100,9 +1116,9 @@ fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block_data: &BasicBlockData<'tcx>
                 }
             }
             TerminatorKind::Unreachable => {}
-            TerminatorKind::Drop { target, unwind, .. } |
-            TerminatorKind::DropAndReplace { target, unwind, .. } |
-            TerminatorKind::Assert {
+            TerminatorKind::Drop { target, unwind, .. }
+            | TerminatorKind::DropAndReplace { target, unwind, .. }
+            TerminatorKind::Assert {
                 target,
                 cleanup: unwind,
                 ..
@@ -1358,13 +1374,13 @@ fn check_rvalue(&mut self, mir: &Mir<'tcx>, rvalue: &Rvalue<'tcx>, location: Loc
             },
 
             // FIXME: These other cases have to be implemented in future PRs
-            Rvalue::Use(..) |
-            Rvalue::Ref(..) |
-            Rvalue::Len(..) |
-            Rvalue::BinaryOp(..) |
-            Rvalue::CheckedBinaryOp(..) |
-            Rvalue::UnaryOp(..) |
-            Rvalue::Discriminant(..) => {}
+            Rvalue::Use(..)
+            | Rvalue::Ref(..)
+            | Rvalue::Len(..)
+            | Rvalue::BinaryOp(..)
+            | Rvalue::CheckedBinaryOp(..)
+            | Rvalue::UnaryOp(..)
+            Rvalue::Discriminant(..) => {}
         }
     }
 
@@ -1498,9 +1514,7 @@ fn prove_predicates(&mut self, predicates: &[ty::Predicate<'tcx>], location: Loc
             let cause = this.misc(this.last_span);
             let obligations = predicates
                 .iter()
-                .map(|&p| {
-                    traits::Obligation::new(cause.clone(), this.param_env, p)
-                })
+                .map(|&p| traits::Obligation::new(cause.clone(), this.param_env, p))
                 .collect();
             Ok(InferOk {
                 value: (),
@@ -1564,7 +1578,7 @@ fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &
         }
         let param_env = tcx.param_env(def_id);
         tcx.infer_ctxt().enter(|infcx| {
-            let _ = type_check_internal(&infcx, id, param_env, mir, None, &mut |_| ());
+            let _ = type_check_internal(&infcx, id, param_env, mir, &[], None, &mut |_| ());
 
             // For verification purposes, we just ignore the resulting
             // region constraint sets. Not our problem. =)
diff --git a/src/test/ui/nll/ty-outlives/projection-implied-bounds.rs b/src/test/ui/nll/ty-outlives/projection-implied-bounds.rs
new file mode 100644 (file)
index 0000000..9a7c283
--- /dev/null
@@ -0,0 +1,56 @@
+// 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
+
+// Test that we can deduce when projections like `T::Item` outlive the
+// function body. Test that this does not imply that `T: 'a` holds.
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+fn twice<F, T>(mut value: T, mut f: F)
+where
+    F: FnMut(&T, Cell<&Option<T::Item>>),
+    T: Iterator,
+{
+    let mut n = value.next();
+    f(&value, Cell::new(&n));
+    f(&value, Cell::new(&n));
+}
+
+#[rustc_errors]
+fn generic1<T: Iterator>(value: T) {
+    // No error here:
+    twice(value, |value_ref, item| invoke1(item));
+}
+
+fn invoke1<'a, T>(x: Cell<&'a Option<T>>)
+where
+    T: 'a,
+{
+}
+
+#[rustc_errors]
+fn generic2<T: Iterator>(value: T) {
+    twice(value, |value_ref, item| invoke2(value_ref, item));
+    //~^ WARNING not reporting region error due to -Znll
+    //~| ERROR `T` does not outlive
+}
+
+fn invoke2<'a, T, U>(a: &T, b: Cell<&'a Option<U>>)
+where
+    T: 'a,
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr b/src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr
new file mode 100644 (file)
index 0000000..6cdf1b6
--- /dev/null
@@ -0,0 +1,14 @@
+warning: not reporting region error due to -Znll
+  --> $DIR/projection-implied-bounds.rs:45:36
+   |
+45 |     twice(value, |value_ref, item| invoke2(value_ref, item));
+   |                                    ^^^^^^^
+
+error: `T` does not outlive `'_#0r`
+  --> $DIR/projection-implied-bounds.rs:45:18
+   |
+45 |     twice(value, |value_ref, item| invoke2(value_ref, item));
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.rs b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.rs
new file mode 100644 (file)
index 0000000..d632bc8
--- /dev/null
@@ -0,0 +1,55 @@
+// 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(dyn_trait)]
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// Invoke in such a way that the callee knows:
+//
+// - 'a: 'x
+//
+// and it must prove that `T: 'x`. Callee passes along `T: 'a`.
+fn twice<'a, F, T>(v: Cell<&'a ()>, value: T, mut f: F)
+where
+    F: for<'x> FnMut(Option<Cell<&'a &'x ()>>, &T),
+{
+    f(None, &value);
+    f(None, &value);
+}
+
+#[rustc_regions]
+fn generic<T>(value: T) {
+    let cell = Cell::new(&());
+    twice(cell, value, |a, b| invoke(a, b));
+    //~^ WARNING not reporting region error
+    //
+    // This error from the old region solver looks bogus.
+}
+
+#[rustc_regions]
+fn generic_fail<'a, T>(cell: Cell<&'a ()>, value: T) {
+    twice(cell, value, |a, b| invoke(a, b));
+    //~^ WARNING not reporting region error
+    //~| WARNING not reporting region error
+    //~| ERROR `T` does not outlive
+}
+
+fn invoke<'a, 'x, T>(x: Option<Cell<&'x &'a ()>>, y: &T)
+where
+    T: 'x,
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
new file mode 100644 (file)
index 0000000..f6ca614
--- /dev/null
@@ -0,0 +1,85 @@
+warning: not reporting region error due to -Znll
+  --> $DIR/ty-param-closure-approximate-lower-bound.rs:35:31
+   |
+35 |     twice(cell, value, |a, b| invoke(a, b));
+   |                               ^^^^^^^^^^^^
+
+warning: not reporting region error due to -Znll
+  --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:31
+   |
+43 |     twice(cell, value, |a, b| invoke(a, b));
+   |                               ^^^^^^
+
+warning: not reporting region error due to -Znll
+  --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:31
+   |
+43 |     twice(cell, value, |a, b| invoke(a, b));
+   |                               ^^^^^^^^^^^^
+
+note: External requirements
+  --> $DIR/ty-param-closure-approximate-lower-bound.rs:35:24
+   |
+35 |     twice(cell, value, |a, b| invoke(a, b));
+   |                        ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:14 ~ ty_param_closure_approximate_lower_bound[317d]::generic[0]::{{closure}}[0]) with closure substs [
+               T,
+               i16,
+               for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) ()>>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) T))
+           ]
+   = note: number of external vids: 2
+   = note: where T: '_#1r
+
+note: External requirements
+  --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:24
+   |
+43 |     twice(cell, value, |a, b| invoke(a, b));
+   |                        ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:17 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]::{{closure}}[0]) with closure substs [
+               T,
+               i16,
+               for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) ()>>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) T))
+           ]
+   = note: number of external vids: 2
+   = note: where T: '_#1r
+
+note: No external requirements
+  --> $DIR/ty-param-closure-approximate-lower-bound.rs:33:1
+   |
+33 | / fn generic<T>(value: T) {
+34 | |     let cell = Cell::new(&());
+35 | |     twice(cell, value, |a, b| invoke(a, b));
+36 | |     //~^ WARNING not reporting region error
+37 | |     //
+38 | |     // This error from the old region solver looks bogus.
+39 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:5 ~ ty_param_closure_approximate_lower_bound[317d]::generic[0]) with substs [
+               T
+           ]
+
+error: `T` does not outlive `'_#3r`
+  --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:24
+   |
+43 |     twice(cell, value, |a, b| invoke(a, b));
+   |                        ^^^^^^^^^^^^^^^^^^^
+
+note: No external requirements
+  --> $DIR/ty-param-closure-approximate-lower-bound.rs:42:1
+   |
+42 | / fn generic_fail<'a, T>(cell: Cell<&'a ()>, value: T) {
+43 | |     twice(cell, value, |a, b| invoke(a, b));
+44 | |     //~^ WARNING not reporting region error
+45 | |     //~| WARNING not reporting region error
+46 | |     //~| ERROR `T` does not outlive
+47 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:6 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]) with substs [
+               T
+           ]
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/ty-outlives/ty-param-implied-bounds.rs b/src/test/ui/nll/ty-outlives/ty-param-implied-bounds.rs
new file mode 100644 (file)
index 0000000..cab7ba7
--- /dev/null
@@ -0,0 +1,42 @@
+// 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
+// must-compile-successfully
+
+// Test that we assume that universal types like `T` outlive the
+// function body.
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+fn twice<F, T>(value: T, mut f: F)
+where
+    F: FnMut(Cell<&T>),
+{
+    f(Cell::new(&value));
+    f(Cell::new(&value));
+}
+
+#[rustc_errors]
+fn generic<T>(value: T) {
+    // No error here:
+    twice(value, |r| invoke(r));
+}
+
+fn invoke<'a, T>(x: Cell<&'a T>)
+where
+    T: 'a,
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/ty-param-implied-bounds.stderr b/src/test/ui/nll/ty-outlives/ty-param-implied-bounds.stderr
new file mode 100644 (file)
index 0000000..e69de29