From cd564d20ff521d56ad3f01fe0e0588d9487c0c13 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 3 Dec 2017 06:16:52 -0500 Subject: only propagate ClosureRegionRequirements if non-trivial Before, we would always have a `Some` ClosureRegionRequirements if we were inferring values for a closure. Now we only do is it has a non-empty set of outlives requirements. --- .../escape-argument-callee.stderr | 3 +- .../closure-requirements/escape-argument.stderr | 3 +- .../propagate-approximated-fail-no-postdom.stderr | 3 +- ...shorter-to-static-comparing-against-free.stderr | 3 +- .../propagate-approximated-to-empty.stderr | 45 ++++++++++++++++++++++ ...ate-fail-to-approximate-longer-no-bounds.stderr | 7 ++-- ...-fail-to-approximate-longer-wrong-bounds.stderr | 7 ++-- .../return-wrong-bound-region.stderr | 3 +- 8 files changed, 56 insertions(+), 18 deletions(-) create mode 100644 src/test/ui/nll/closure-requirements/propagate-approximated-to-empty.stderr (limited to 'src/test') diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr index c842d51a2ad..2dfafd8f172 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr @@ -10,7 +10,7 @@ error: free region `'_#4r` does not outlive free region `'_#3r` 36 | let mut closure = expect_sig(|p, y| *p = y); | ^^^^^^ -note: External requirements +note: No external requirements --> $DIR/escape-argument-callee.rs:36:38 | 36 | let mut closure = expect_sig(|p, y| *p = y); @@ -20,7 +20,6 @@ note: External requirements i16, for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) mut &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) i32, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't0)) i32)) ] - = note: number of external vids: 1 note: No external requirements --> $DIR/escape-argument-callee.rs:30:1 diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr index 0ec671997e7..567ed299ac1 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr @@ -1,4 +1,4 @@ -note: External requirements +note: No external requirements --> $DIR/escape-argument.rs:36:38 | 36 | let mut closure = expect_sig(|p, y| *p = y); @@ -8,7 +8,6 @@ note: External requirements i16, for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) mut &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) i32, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) i32)) ] - = note: number of external vids: 1 note: No external requirements --> $DIR/escape-argument.rs:30:1 diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr index d581622c4c6..cdda8ab5392 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -10,7 +10,7 @@ error: free region `'_#5r` does not outlive free region `'_#6r` 57 | demand_y(x, y, p) | ^ -note: External requirements +note: No external requirements --> $DIR/propagate-approximated-fail-no-postdom.rs:53:9 | 53 | / |_outlives1, _outlives2, _outlives3, x, y| { @@ -26,7 +26,6 @@ note: External requirements i16, for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>)) ] - = note: number of external vids: 4 note: No external requirements --> $DIR/propagate-approximated-fail-no-postdom.rs:48:1 diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index b93c69dc13f..3e54e62d011 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -10,7 +10,7 @@ error: free region `'_#2r` does not outlive free region `'_#1r` 33 | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure | ^^^^^^ -note: External requirements +note: No external requirements --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:31:15 | 31 | foo(cell, |cell_a, cell_x| { @@ -25,7 +25,6 @@ note: External requirements i32, for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>)) ] - = note: number of external vids: 2 note: No external requirements --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:28:1 diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-to-empty.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-to-empty.stderr new file mode 100644 index 00000000000..e8dc8a13f87 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-to-empty.stderr @@ -0,0 +1,45 @@ +warning: not reporting region error due to -Znll + --> $DIR/propagate-approximated-to-empty.rs:41:9 + | +41 | demand_y(x, y, x.get()) + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: free region `'_#6r` does not outlive free region `'_#4r` + --> $DIR/propagate-approximated-to-empty.rs:41:21 + | +41 | demand_y(x, y, x.get()) + | ^ + +note: No external requirements + --> $DIR/propagate-approximated-to-empty.rs:39:47 + | +39 | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { + | _______________________________________________^ +40 | | // Only works if 'x: 'y: +41 | | demand_y(x, y, x.get()) +42 | | //~^ WARN not reporting region error due to -Znll +43 | | //~| ERROR free region `'_#6r` does not outlive free region `'_#4r` +44 | | }); + | |_____^ + | + = note: defining type: DefId(0/1:18 ~ propagate_approximated_to_empty[317d]::supply[0]::{{closure}}[0]) with closure substs [ + i16, + for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>)) + ] + +note: No external requirements + --> $DIR/propagate-approximated-to-empty.rs:38:1 + | +38 | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { +39 | | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { +40 | | // Only works if 'x: 'y: +41 | | demand_y(x, y, x.get()) +... | +44 | | }); +45 | | } + | |_^ + | + = note: defining type: DefId(0/0:6 ~ propagate_approximated_to_empty[317d]::supply[0]) with substs [] + +error: aborting due to previous error + diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index 6094f9aad81..f3c40c838fb 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -5,12 +5,12 @@ warning: not reporting region error due to -Znll | ^^^^^^^^^^^^^^^^^^^^^^^ error: free region `'_#6r` does not outlive free region `'_#4r` - --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:21 + --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:18 | 47 | demand_y(x, y, x.get()) - | ^ + | ^ -note: External requirements +note: No external requirements --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:45:47 | 45 | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { @@ -26,7 +26,6 @@ note: External requirements i16, for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>)) ] - = note: number of external vids: 2 note: No external requirements --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:44:1 diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr index 6658ee63abd..a66c2a78970 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr @@ -5,12 +5,12 @@ warning: not reporting region error due to -Znll | ^^^^^^^^^^^^^^^^^^^^^^^ error: free region `'_#5r` does not outlive free region `'_#7r` - --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:51:21 + --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:51:18 | 51 | demand_y(x, y, x.get()) - | ^ + | ^ -note: External requirements +note: No external requirements --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:49:47 | 49 | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { @@ -26,7 +26,6 @@ note: External requirements i16, for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't1)) u32>)) ] - = note: number of external vids: 3 note: No external requirements --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:48:1 diff --git a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr index 8999f69e8de..cb2b2e2f118 100644 --- a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr +++ b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr @@ -10,7 +10,7 @@ error: free region `'_#3r` does not outlive free region `'_#2r` 21 | expect_sig(|a, b| b); // ought to return `a` | ^ -note: External requirements +note: No external requirements --> $DIR/return-wrong-bound-region.rs:21:16 | 21 | expect_sig(|a, b| b); // ought to return `a` @@ -20,7 +20,6 @@ note: External requirements i16, for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) i32, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) i32)) -> &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) i32 ] - = note: number of external vids: 1 note: No external requirements --> $DIR/return-wrong-bound-region.rs:20:1 -- cgit 1.4.1-3-g733a5 From 6193c5cc2acd1c427a372dfdab3d071e880ecf62 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 3 Dec 2017 07:01:09 -0500 Subject: translate `Verify`s into `TypeTest`s and check them --- .../borrow_check/nll/region_infer/dfs.rs | 48 +++-- .../borrow_check/nll/region_infer/mod.rs | 220 ++++++++++++++++++++- .../nll/subtype_constraint_generation.rs | 68 ++++++- src/test/ui/nll/ty-outlives/ty-param-fn.rs | 51 +++++ src/test/ui/nll/ty-outlives/ty-param-fn.stderr | 26 +++ 5 files changed, 389 insertions(+), 24 deletions(-) create mode 100644 src/test/ui/nll/ty-outlives/ty-param-fn.rs create mode 100644 src/test/ui/nll/ty-outlives/ty-param-fn.stderr (limited to 'src/test') diff --git a/src/librustc_mir/borrow_check/nll/region_infer/dfs.rs b/src/librustc_mir/borrow_check/nll/region_infer/dfs.rs index c8ac0fa233f..dcf5d979a4c 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/dfs.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/dfs.rs @@ -11,11 +11,12 @@ //! Module defining the `dfs` method on `RegionInferenceContext`, along with //! its associated helper traits. +use borrow_check::nll::universal_regions::UniversalRegions; +use borrow_check::nll::region_infer::RegionInferenceContext; +use borrow_check::nll::region_infer::values::{RegionElementIndex, RegionValues, RegionValueElements}; use rustc::mir::{Location, Mir}; use rustc::ty::RegionVid; use rustc_data_structures::fx::FxHashSet; -use super::RegionInferenceContext; -use super::values::{RegionElementIndex, RegionValues, RegionValueElements}; impl<'tcx> RegionInferenceContext<'tcx> { /// Function used to satisfy or test a `R1: R2 @ P` @@ -165,17 +166,16 @@ impl<'v> DfsOp for CopyFromSourceToTarget<'v> { /// condition. Similarly, if we reach the end of the graph and find /// that R1 contains some universal region that R2 does not contain, /// we abort the walk early. -#[allow(dead_code)] // TODO -pub(super) struct TestTarget<'v> { - source_region: RegionVid, - target_region: RegionVid, - elements: &'v RegionValueElements, - inferred_values: &'v RegionValues, - constraint_point: Location, +pub(super) struct TestTargetOutlivesSource<'v, 'tcx: 'v> { + pub source_region: RegionVid, + pub target_region: RegionVid, + pub elements: &'v RegionValueElements, + pub universal_regions: &'v UniversalRegions<'tcx>, + pub inferred_values: &'v RegionValues, + pub constraint_point: Location, } -#[allow(dead_code)] // TODO -impl<'v> DfsOp for TestTarget<'v> { +impl<'v, 'tcx> DfsOp for TestTargetOutlivesSource<'v, 'tcx> { /// The element that was not found within R2. type Early = RegionElementIndex; @@ -204,12 +204,32 @@ impl<'v> DfsOp for TestTarget<'v> { fn add_universal_regions_outlived_by_source_to_target( &mut self, ) -> Result { - for ur in self.inferred_values + // For all `ur_in_source` in `source_region`. + for ur_in_source in self.inferred_values .universal_regions_outlived_by(self.source_region) { - if !self.inferred_values.contains(self.target_region, ur) { - return Err(self.elements.index(ur)); + // Check that `target_region` outlives `ur_in_source`. + + // If `ur_in_source` is a member of `target_region`, OK. + // + // (This is implied by the loop below, actually, just an + // irresistible micro-opt. Mm. Premature optimization. So + // tasty.) + if self.inferred_values.contains(self.target_region, ur_in_source) { + continue; } + + // If there is some other element X such that `target_region: X` and + // `X: ur_in_source`, OK. + if self.inferred_values + .universal_regions_outlived_by(self.target_region) + .any(|ur_in_target| self.universal_regions.outlives(ur_in_target, ur_in_source)) + { + continue; + } + + // Otherwise, not known to be true. + return Err(self.elements.index(ur_in_source)); } Ok(false) 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 af88edc22ce..86ba7524bf0 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -14,7 +14,7 @@ use rustc::infer::InferCtxt; use rustc::infer::NLLRegionVariableOrigin; use rustc::infer::RegionVariableOrigin; use rustc::infer::SubregionOrigin; -use rustc::infer::region_constraints::VarOrigins; +use rustc::infer::region_constraints::{GenericKind, VarOrigins}; use rustc::mir::{ClosureOutlivesRequirement, ClosureRegionRequirements, Location, Mir}; use rustc::ty::{self, RegionVid}; use rustc_data_structures::indexed_vec::IndexVec; @@ -24,7 +24,7 @@ use syntax_pos::Span; mod annotation; mod dfs; -use self::dfs::CopyFromSourceToTarget; +use self::dfs::{CopyFromSourceToTarget, TestTargetOutlivesSource}; mod dump_mir; mod graphviz; mod values; @@ -53,6 +53,9 @@ pub struct RegionInferenceContext<'tcx> { /// The constraints we have accumulated and used during solving. constraints: Vec, + /// Type constraints that we check after solving. + type_tests: Vec>, + /// Information about the universally quantified regions in scope /// on this function and their (known) relations to one another. universal_regions: UniversalRegions<'tcx>, @@ -95,6 +98,90 @@ pub struct Constraint { span: Span, } +/// A "type test" corresponds to an outlives constraint between a type +/// and a lifetime, like `T: 'x` or `::Bar: 'x`. They are +/// translated from the `Verify` region constraints in the ordinary +/// inference context. +/// +/// These sorts of constraints are handled differently than ordinary +/// constraints, at least at present. During type checking, the +/// `InferCtxt::process_registered_region_obligations` method will +/// attempt to convert a type test like `T: 'x` into an ordinary +/// outlives constraint when possible (for example, `&'a T: 'b` will +/// be converted into `'a: 'b` and registered as a `Constraint`). +/// +/// In some cases, however, there are outlives relationships that are +/// not converted into a region constraint, but rather into one of +/// these "type tests". The distinction is that a type test does not +/// influence the inference result, but instead just examines the +/// values that we ultimately inferred for each region variable and +/// checks that they meet certain extra criteria. If not, an error +/// can be issued. +/// +/// One reason for this is that these type tests always boil down to a +/// check like `'a: 'x` where `'a` is a universally quantified region +/// -- and therefore not one whose value is really meant to be +/// *inferred*, precisely. Another reason is that these type tests can +/// involve *disjunction* -- that is, they can be satisfied in more +/// than one way. +/// +/// For more information about this translation, see +/// `InferCtxt::process_registered_region_obligations` and +/// `InferCtxt::type_must_outlive` in `rustc::infer::outlives`. +#[derive(Clone, Debug)] +pub struct TypeTest<'tcx> { + /// The type `T` that must outlive the region. + pub generic_kind: GenericKind<'tcx>, + + /// The region `'x` that the type must outlive. + pub lower_bound: RegionVid, + + /// The point where the outlives relation must hold. + pub point: Location, + + /// Where did this constraint arise? + pub span: Span, + + /// A test which, if met by the region `'x`, proves that this type + /// constraint is satisfied. + pub test: RegionTest, +} + +/// A "test" that can be applied to some "subject region" `'x`. These are used to +/// describe type constraints. Tests do not presently affect the +/// region values that get inferred for each variable; they only +/// examine the results *after* inference. This means they can +/// conveniently include disjuction ("a or b must be true"). +#[derive(Clone, Debug)] +pub enum RegionTest { + /// The subject region `'x` must by outlived by *some* region in + /// the given set of regions. + /// + /// This test comes from e.g. a where clause like `T: 'a + 'b`, + /// which implies that we know that `T: 'a` and that `T: + /// 'b`. Therefore, if we are trying to prove that `T: 'x`, we can + /// do so by showing that `'a: 'x` *or* `'b: 'x`. + IsOutlivedByAnyRegionIn(Vec), + + /// The subject region `'x` must by outlived by *all* regions in + /// the given set of regions. + /// + /// This test comes from e.g. a projection type like `T = >::Foo`, which must outlive `'a` or `'b`, and + /// maybe both. Therefore we can prove that `T: 'x` if we know + /// that `'a: 'x` *and* `'b: 'x`. + IsOutlivedByAllRegionsIn(Vec), + + /// Any of the given tests are true. + /// + /// This arises from projections, for which there are multiple + /// ways to prove an outlives relationship. + Any(Vec), + + /// All of the given tests are true. + All(Vec), +} + impl<'tcx> RegionInferenceContext<'tcx> { /// Creates a new region inference context with a total of /// `num_region_variables` valid inference variables; the first N @@ -122,6 +209,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { liveness_constraints: RegionValues::new(elements, num_region_variables), inferred_values: None, constraints: Vec::new(), + type_tests: Vec::new(), universal_regions, }; @@ -243,7 +331,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { }); } - /// Perform region inference. + /// Add a "type test" that must be satisfied. + pub(super) fn add_type_test(&mut self, type_test: TypeTest<'tcx>) { + self.type_tests.push(type_test); + } + + /// Perform region inference and report errors if we see any + /// unsatisfiable constraints. If this is a closure, returns the + /// region requirements to propagate to our creator, if any. pub(super) fn solve( &mut self, infcx: &InferCtxt<'_, '_, 'tcx>, @@ -254,6 +349,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.propagate_constraints(mir); + self.check_type_tests(infcx, mir); + let outlives_requirements = self.check_universal_regions(infcx, mir_def_id); if outlives_requirements.is_empty() { @@ -315,6 +412,123 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.inferred_values = Some(inferred_values); } + /// Once regions have been propagated, this method is used to see + /// whether any of the constraints were too strong. In particular, + /// we want to check for a case where a universally quantified + /// region exceeded its bounds. Consider: + /// + /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x } + /// + /// In this case, returning `x` requires `&'a u32 <: &'b u32` + /// and hence we establish (transitively) a constraint that + /// `'a: 'b`. The `propagate_constraints` code above will + /// therefore add `end('a)` into the region for `'b` -- but we + /// have no evidence that `'b` outlives `'a`, so we want to report + /// an error. + fn check_type_tests( + &self, + infcx: &InferCtxt<'_, '_, 'tcx>, + mir: &Mir<'tcx>, + ) { + for type_test in &self.type_tests { + debug!("check_type_test: {:?}", type_test); + + if !self.eval_region_test( + mir, + type_test.point, + type_test.lower_bound, + &type_test.test, + ) { + // Oh the humanity. Obviously we will do better than this error eventually. + infcx.tcx.sess.span_err( + type_test.span, + &format!("failed type test: {:?}", type_test), + ); + } + } + } + + /// Test if `test` is true when applied to `lower_bound` at + /// `point`, and returns true or false. + fn eval_region_test( + &self, + mir: &Mir<'tcx>, + point: Location, + lower_bound: RegionVid, + test: &RegionTest, + ) -> bool { + debug!( + "eval_region_test(point={:?}, lower_bound={:?}, test={:?})", + point, + lower_bound, + test + ); + + match test { + RegionTest::IsOutlivedByAllRegionsIn(regions) => regions + .iter() + .all(|&r| self.eval_outlives(mir, r, lower_bound, point)), + + RegionTest::IsOutlivedByAnyRegionIn(regions) => regions + .iter() + .any(|&r| self.eval_outlives(mir, r, lower_bound, point)), + + RegionTest::Any(tests) => tests + .iter() + .any(|test| self.eval_region_test(mir, point, lower_bound, test)), + + RegionTest::All(tests) => tests + .iter() + .all(|test| self.eval_region_test(mir, point, lower_bound, test)), + } + } + + // Evaluate whether `sup_region: sub_region @ point`. + fn eval_outlives( + &self, + mir: &Mir<'tcx>, + sup_region: RegionVid, + sub_region: RegionVid, + point: Location, + ) -> bool { + debug!( + "eval_outlives({:?}: {:?} @ {:?})", + sup_region, + sub_region, + point + ); + + // Roughly speaking, do a DFS of all region elements reachable + // from `point` contained in `sub_region`. If any of those are + // *not* present in `sup_region`, the DFS will abort early and + // yield an `Err` result. + match self.dfs( + mir, + TestTargetOutlivesSource { + source_region: sub_region, + target_region: sup_region, + constraint_point: point, + elements: &self.elements, + universal_regions: &self.universal_regions, + inferred_values: self.inferred_values.as_ref().unwrap(), + }, + ) { + Ok(_) => { + debug!("eval_outlives: true"); + true + } + + Err(elem) => { + debug!( + "eval_outlives: false because `{:?}` is not present in `{:?}`", + self.elements.to_element(elem), + sup_region + ); + false + } + } + } + /// Once regions have been propagated, this method is used to see /// whether any of the constraints were too strong. In particular, /// we want to check for a case where a universally quantified diff --git a/src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs b/src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs index c98a94fa8bc..73c40827c54 100644 --- a/src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs @@ -11,11 +11,14 @@ use rustc::mir::Mir; use rustc::infer::region_constraints::Constraint; use rustc::infer::region_constraints::RegionConstraintData; +use rustc::infer::region_constraints::{Verify, VerifyBound}; use rustc::ty; +use syntax::codemap::Span; +use transform::type_check::Locations; use transform::type_check::MirTypeckRegionConstraints; use transform::type_check::OutlivesSet; -use super::region_infer::RegionInferenceContext; +use super::region_infer::{TypeTest, RegionInferenceContext, RegionTest}; /// When the MIR type-checker executes, it validates all the types in /// the MIR, and in the process generates a set of constraints that @@ -27,10 +30,7 @@ pub(super) fn generate<'tcx>( mir: &Mir<'tcx>, constraints: &MirTypeckRegionConstraints<'tcx>, ) { - SubtypeConstraintGenerator { - regioncx, - mir, - }.generate(constraints); + SubtypeConstraintGenerator { regioncx, mir }.generate(constraints); } struct SubtypeConstraintGenerator<'cx, 'tcx: 'cx> { @@ -65,6 +65,8 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> { givens, } = data; + let span = self.mir.source_info(locations.from_location).span; + for constraint in constraints.keys() { debug!("generate: constraint: {:?}", constraint); let (a_vid, b_vid) = match constraint { @@ -81,12 +83,15 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> { // reverse direction, because `regioncx` talks about // "outlives" (`>=`) whereas the region constraints // talk about `<=`. - let span = self.mir.source_info(locations.from_location).span; self.regioncx .add_outlives(span, b_vid, a_vid, locations.at_location); } - assert!(verifys.is_empty(), "verifys not yet implemented"); + for verify in verifys { + let type_test = self.verify_to_type_test(verify, span, locations); + self.regioncx.add_type_test(type_test); + } + assert!( givens.is_empty(), "MIR type-checker does not use givens (thank goodness)" @@ -94,6 +99,55 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> { } } + fn verify_to_type_test( + &self, + verify: &Verify<'tcx>, + span: Span, + locations: &Locations, + ) -> TypeTest<'tcx> { + let generic_kind = verify.kind; + + let lower_bound = self.to_region_vid(verify.region); + + let point = locations.at_location; + + let test = self.verify_bound_to_region_test(&verify.bound); + + TypeTest { + generic_kind, + lower_bound, + point, + span, + test, + } + } + + fn verify_bound_to_region_test(&self, verify_bound: &VerifyBound<'tcx>) -> RegionTest { + match verify_bound { + VerifyBound::AnyRegion(regions) => RegionTest::IsOutlivedByAnyRegionIn( + regions.iter().map(|r| self.to_region_vid(r)).collect(), + ), + + VerifyBound::AllRegions(regions) => RegionTest::IsOutlivedByAllRegionsIn( + regions.iter().map(|r| self.to_region_vid(r)).collect(), + ), + + VerifyBound::AnyBound(bounds) => RegionTest::Any( + bounds + .iter() + .map(|b| self.verify_bound_to_region_test(b)) + .collect(), + ), + + VerifyBound::AllBounds(bounds) => RegionTest::All( + bounds + .iter() + .map(|b| self.verify_bound_to_region_test(b)) + .collect(), + ), + } + } + fn to_region_vid(&self, r: ty::Region<'tcx>) -> ty::RegionVid { // Every region that we see in the constraints came from the // MIR or from the parameter environment. If the former, it diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn.rs b/src/test/ui/nll/ty-outlives/ty-param-fn.rs new file mode 100644 index 00000000000..c6547ae68fa --- /dev/null +++ b/src/test/ui/nll/ty-outlives/ty-param-fn.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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-Znll -Zborrowck=mir + +#![allow(warnings)] +#![feature(dyn_trait)] + +use std::fmt::Debug; + +fn no_region<'a, T>(x: Box) -> Box +where + T: Debug, +{ + x + //~^ WARNING not reporting region error due to -Znll + //~| ERROR failed type test +} + +fn correct_region<'a, T>(x: Box) -> Box +where + T: 'a + Debug, +{ + x +} + +fn wrong_region<'a, 'b, T>(x: Box) -> Box +where + T: 'b + Debug, +{ + x + //~^ WARNING not reporting region error due to -Znll + //~| ERROR failed type test +} + +fn outlives_region<'a, 'b, T>(x: Box) -> Box +where + T: 'b + Debug, + 'b: 'a, +{ + x +} + +fn main() {} diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn.stderr b/src/test/ui/nll/ty-outlives/ty-param-fn.stderr new file mode 100644 index 00000000000..5b29ff88621 --- /dev/null +++ b/src/test/ui/nll/ty-outlives/ty-param-fn.stderr @@ -0,0 +1,26 @@ +warning: not reporting region error due to -Znll + --> $DIR/ty-param-fn.rs:22:5 + | +22 | x + | ^ + +warning: not reporting region error due to -Znll + --> $DIR/ty-param-fn.rs:38:5 + | +38 | x + | ^ + +error: failed type test: TypeTest { generic_kind: T/#1, lower_bound: '_#2r, point: bb0[3], span: $DIR/ty-param-fn.rs:22:5: 22:6, test: IsOutlivedByAnyRegionIn([]) } + --> $DIR/ty-param-fn.rs:22:5 + | +22 | x + | ^ + +error: failed type test: TypeTest { generic_kind: T/#2, lower_bound: '_#3r, point: bb0[3], span: $DIR/ty-param-fn.rs:38:5: 38:6, test: IsOutlivedByAnyRegionIn(['_#2r]) } + --> $DIR/ty-param-fn.rs:38:5 + | +38 | x + | ^ + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 47c1921b9adb7c6e783ef4ec2a5f1dbe312b3da7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 3 Dec 2017 13:14:36 -0500 Subject: move some parts of liveness to happen during type checking This allows us to re-use the `normalize` method on `TypeCheck`, which is important since normalization may create fresh region variables. This is not an ideal solution, though, since the current representation of "liveness constraints" (a vector of (region, point) pairs) is rather inefficient. Could do somewhat better by converting to indices, but it'd still be less good than the older code. Unclear how important this is. --- .../borrow_check/nll/constraint_generation.rs | 173 +--------------- src/librustc_mir/borrow_check/nll/mod.rs | 23 ++- .../borrow_check/nll/region_infer/mod.rs | 18 +- .../borrow_check/nll/type_check/liveness.rs | 220 +++++++++++++++++++++ .../borrow_check/nll/type_check/mod.rs | 37 +++- src/test/ui/nll/ty-outlives/projection-fn.rs | 53 +++++ src/test/ui/nll/ty-outlives/projection-fn.stderr | 26 +++ 7 files changed, 351 insertions(+), 199 deletions(-) create mode 100644 src/librustc_mir/borrow_check/nll/type_check/liveness.rs create mode 100644 src/test/ui/nll/ty-outlives/projection-fn.rs create mode 100644 src/test/ui/nll/ty-outlives/projection-fn.stderr (limited to 'src/test') diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 5564a0d98af..673e85e6b61 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -12,21 +12,13 @@ use rustc::hir; use rustc::mir::{BasicBlock, BasicBlockData, Location, Place, Mir, Rvalue}; use rustc::mir::visit::Visitor; use rustc::mir::Place::Projection; -use rustc::mir::{Local, PlaceProjection, ProjectionElem}; +use rustc::mir::{PlaceProjection, ProjectionElem}; use rustc::mir::visit::TyContext; use rustc::infer::InferCtxt; -use rustc::traits::{self, ObligationCause}; -use rustc::ty::{self, ClosureSubsts, Ty}; +use rustc::ty::{self, ClosureSubsts}; use rustc::ty::subst::Substs; use rustc::ty::fold::TypeFoldable; -use rustc::util::common::ErrorReported; -use rustc_data_structures::fx::FxHashSet; -use syntax::codemap::DUMMY_SP; -use dataflow::{FlowAtLocation, FlowsAtLocation}; -use dataflow::MaybeInitializedLvals; -use dataflow::move_paths::{HasMoveData, MoveData}; -use super::LivenessResults; use super::ToRegionVid; use super::region_infer::RegionInferenceContext; @@ -34,19 +26,11 @@ pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>( infcx: &InferCtxt<'cx, 'gcx, 'tcx>, regioncx: &mut RegionInferenceContext<'tcx>, mir: &Mir<'tcx>, - param_env: ty::ParamEnv<'tcx>, - liveness: &LivenessResults, - flow_inits: &mut FlowAtLocation>, - move_data: &MoveData<'tcx>, ) { let mut cg = ConstraintGeneration { infcx, regioncx, mir, - liveness, - param_env, - flow_inits, - move_data, }; for (bb, data) in mir.basic_blocks().iter_enumerated() { @@ -59,16 +43,10 @@ struct ConstraintGeneration<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> { infcx: &'cg InferCtxt<'cx, 'gcx, 'tcx>, regioncx: &'cg mut RegionInferenceContext<'tcx>, mir: &'cg Mir<'tcx>, - liveness: &'cg LivenessResults, - param_env: ty::ParamEnv<'tcx>, - flow_inits: &'cg mut FlowAtLocation>, - move_data: &'cg MoveData<'tcx>, } - impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx, 'tcx> { fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) { - self.add_liveness_constraints(bb); self.super_basic_block_data(bb, data); } @@ -130,84 +108,6 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx } impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> { - /// Liveness constraints: - /// - /// > If a variable V is live at point P, then all regions R in the type of V - /// > must include the point P. - fn add_liveness_constraints(&mut self, bb: BasicBlock) { - debug!("add_liveness_constraints(bb={:?})", bb); - - self.liveness - .regular - .simulate_block(self.mir, bb, |location, live_locals| { - for live_local in live_locals.iter() { - let live_local_ty = self.mir.local_decls[live_local].ty; - self.add_regular_live_constraint(live_local_ty, location); - } - }); - - let mut all_live_locals: Vec<(Location, Vec)> = vec![]; - self.liveness - .drop - .simulate_block(self.mir, bb, |location, live_locals| { - all_live_locals.push((location, live_locals.iter().collect())); - }); - debug!( - "add_liveness_constraints: all_live_locals={:#?}", - all_live_locals - ); - - let terminator_index = self.mir.basic_blocks()[bb].statements.len(); - self.flow_inits.reset_to_entry_of(bb); - while let Some((location, live_locals)) = all_live_locals.pop() { - for live_local in live_locals { - debug!( - "add_liveness_constraints: location={:?} live_local={:?}", - location, - live_local - ); - - self.flow_inits.each_state_bit(|mpi_init| { - debug!( - "add_liveness_constraints: location={:?} initialized={:?}", - location, - &self.flow_inits - .operator() - .move_data() - .move_paths[mpi_init] - ); - }); - - let mpi = self.move_data.rev_lookup.find_local(live_local); - if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) { - debug!( - "add_liveness_constraints: mpi={:?} has initialized child {:?}", - self.move_data.move_paths[mpi], - self.move_data.move_paths[initialized_child] - ); - - let live_local_ty = self.mir.local_decls[live_local].ty; - self.add_drop_live_constraint(live_local_ty, location); - } - } - - if location.statement_index == terminator_index { - debug!( - "add_liveness_constraints: reconstruct_terminator_effect from {:#?}", - location - ); - self.flow_inits.reconstruct_terminator_effect(location); - } else { - debug!( - "add_liveness_constraints: reconstruct_statement_effect from {:#?}", - location - ); - self.flow_inits.reconstruct_statement_effect(location); - } - self.flow_inits.apply_local_effect(location); - } - } - /// Some variable with type `live_ty` is "regular live" at /// `location` -- i.e., it may be used later. This means that all /// regions appearing in the type `live_ty` must be live at @@ -230,75 +130,6 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> { }); } - /// Some variable with type `live_ty` is "drop live" at `location` - /// -- i.e., it may be dropped later. This means that *some* of - /// the regions in its type must be live at `location`. The - /// precise set will depend on the dropck constraints, and in - /// particular this takes `#[may_dangle]` into account. - fn add_drop_live_constraint(&mut self, dropped_ty: Ty<'tcx>, location: Location) { - debug!( - "add_drop_live_constraint(dropped_ty={:?}, location={:?})", - dropped_ty, - location - ); - - let tcx = self.infcx.tcx; - let mut types = vec![(dropped_ty, 0)]; - let mut known = FxHashSet(); - while let Some((ty, depth)) = types.pop() { - let span = DUMMY_SP; // FIXME - let result = match tcx.dtorck_constraint_for_ty(span, dropped_ty, depth, ty) { - Ok(result) => result, - Err(ErrorReported) => { - continue; - } - }; - - let ty::DtorckConstraint { - outlives, - dtorck_types, - } = result; - - // All things in the `outlives` array may be touched by - // the destructor and must be live at this point. - for outlive in outlives { - self.add_regular_live_constraint(outlive, location); - } - - // However, there may also be some types that - // `dtorck_constraint_for_ty` could not resolve (e.g., - // associated types and parameters). We need to normalize - // associated types here and possibly recursively process. - for ty in dtorck_types { - let cause = ObligationCause::dummy(); - // We know that our original `dropped_ty` is well-formed, - // so region obligations resulting from this normalization - // should always hold. - // - // Therefore we ignore them instead of trying to match - // them up with a location. - let fulfillcx = traits::FulfillmentContext::new_ignoring_regions(); - match traits::fully_normalize_with_fulfillcx( - self.infcx, fulfillcx, cause, self.param_env, &ty - ) { - Ok(ty) => match ty.sty { - ty::TyParam(..) | ty::TyProjection(..) | ty::TyAnon(..) => { - self.add_regular_live_constraint(ty, location); - } - - _ => if known.insert(ty) { - types.push((ty, depth + 1)); - }, - }, - - Err(errors) => { - self.infcx.report_fulfillment_errors(&errors, None); - } - } - } - } - } - fn add_reborrow_constraint( &mut self, location: Location, diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index c616f027331..3329448e2b7 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -77,7 +77,16 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( ) { // Run the MIR type-checker. let mir_node_id = infcx.tcx.hir.as_local_node_id(def_id).unwrap(); - let constraint_sets = &type_check::type_check(infcx, mir_node_id, param_env, mir); + let liveness = &LivenessResults::compute(mir); + let constraint_sets = &type_check::type_check( + infcx, + mir_node_id, + param_env, + mir, + &liveness, + flow_inits, + move_data, + ); // Create the region inference context, taking ownership of the region inference // data that was contained in `infcx`. @@ -85,19 +94,9 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( let mut regioncx = RegionInferenceContext::new(var_origins, universal_regions, mir); subtype_constraint_generation::generate(&mut regioncx, mir, constraint_sets); - // Compute what is live where. - let liveness = &LivenessResults::compute(mir); // Generate non-subtyping constraints. - constraint_generation::generate_constraints( - infcx, - &mut regioncx, - &mir, - param_env, - liveness, - flow_inits, - move_data, - ); + constraint_generation::generate_constraints(infcx, &mut regioncx, &mir); // Solve the region constraints. let closure_region_requirements = regioncx.solve(infcx, &mir, def_id); 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 86ba7524bf0..f36392c9fcf 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -425,11 +425,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// therefore add `end('a)` into the region for `'b` -- but we /// have no evidence that `'b` outlives `'a`, so we want to report /// an error. - fn check_type_tests( - &self, - infcx: &InferCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, - ) { + fn check_type_tests(&self, infcx: &InferCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) { for type_test in &self.type_tests { debug!("check_type_test: {:?}", type_test); @@ -473,13 +469,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { .iter() .any(|&r| self.eval_outlives(mir, r, lower_bound, point)), - RegionTest::Any(tests) => tests - .iter() - .any(|test| self.eval_region_test(mir, point, lower_bound, test)), + RegionTest::Any(tests) => tests.iter().any(|test| { + self.eval_region_test(mir, point, lower_bound, test) + }), - RegionTest::All(tests) => tests - .iter() - .all(|test| self.eval_region_test(mir, point, lower_bound, test)), + RegionTest::All(tests) => tests.iter().all(|test| { + self.eval_region_test(mir, point, lower_bound, test) + }), } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs new file mode 100644 index 00000000000..e41bf7cda8e --- /dev/null +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs @@ -0,0 +1,220 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use dataflow::{FlowAtLocation, FlowsAtLocation}; +use dataflow::MaybeInitializedLvals; +use dataflow::move_paths::{HasMoveData, MoveData}; +use rustc::mir::{BasicBlock, Location, Mir}; +use rustc::mir::Local; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::util::common::ErrorReported; +use rustc_data_structures::fx::FxHashSet; +use syntax::codemap::DUMMY_SP; +use util::liveness::LivenessResults; + +use super::TypeChecker; + +/// Combines liveness analysis with initialization analysis to +/// determine which variables are live at which points, both due to +/// ordinary uses and drops. Returns a set of (ty, location) pairs +/// that indicate which types must be live at which point in the CFG. +/// This vector is consumed by `constraint_generation`. +/// +/// NB. This computation requires normalization; therefore, it must be +/// performed before +pub(super) fn generate<'gcx, 'tcx>( + cx: &mut TypeChecker<'_, 'gcx, 'tcx>, + mir: &Mir<'tcx>, + liveness: &LivenessResults, + flow_inits: &mut FlowAtLocation>, + move_data: &MoveData<'tcx>, +) { + let tcx = cx.tcx(); + let mut generator = TypeLivenessGenerator { + cx, + tcx, + mir, + liveness, + flow_inits, + move_data, + }; + + for bb in mir.basic_blocks().indices() { + generator.add_liveness_constraints(bb); + } +} + +struct TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx> +where + 'typeck: 'gen, + 'flow: 'gen, + 'tcx: 'typeck + 'flow, + 'gcx: 'tcx, +{ + cx: &'gen mut TypeChecker<'typeck, 'gcx, 'tcx>, + tcx: TyCtxt<'typeck, 'gcx, 'tcx>, + mir: &'gen Mir<'tcx>, + liveness: &'gen LivenessResults, + flow_inits: &'gen mut FlowAtLocation>, + move_data: &'gen MoveData<'tcx>, +} + +impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx> { + /// Liveness constraints: + /// + /// > If a variable V is live at point P, then all regions R in the type of V + /// > must include the point P. + fn add_liveness_constraints(&mut self, bb: BasicBlock) { + debug!("add_liveness_constraints(bb={:?})", bb); + + self.liveness + .regular + .simulate_block(self.mir, bb, |location, live_locals| { + for live_local in live_locals.iter() { + let live_local_ty = self.mir.local_decls[live_local].ty; + self.push_type_live_constraint(live_local_ty, location); + } + }); + + let mut all_live_locals: Vec<(Location, Vec)> = vec![]; + self.liveness + .drop + .simulate_block(self.mir, bb, |location, live_locals| { + all_live_locals.push((location, live_locals.iter().collect())); + }); + debug!( + "add_liveness_constraints: all_live_locals={:#?}", + all_live_locals + ); + + let terminator_index = self.mir.basic_blocks()[bb].statements.len(); + self.flow_inits.reset_to_entry_of(bb); + while let Some((location, live_locals)) = all_live_locals.pop() { + for live_local in live_locals { + debug!( + "add_liveness_constraints: location={:?} live_local={:?}", + location, + live_local + ); + + self.flow_inits.each_state_bit(|mpi_init| { + debug!( + "add_liveness_constraints: location={:?} initialized={:?}", + location, + &self.flow_inits.operator().move_data().move_paths[mpi_init] + ); + }); + + let mpi = self.move_data.rev_lookup.find_local(live_local); + if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) { + debug!( + "add_liveness_constraints: mpi={:?} has initialized child {:?}", + self.move_data.move_paths[mpi], + self.move_data.move_paths[initialized_child] + ); + + let live_local_ty = self.mir.local_decls[live_local].ty; + self.add_drop_live_constraint(live_local_ty, location); + } + } + + if location.statement_index == terminator_index { + debug!( + "add_liveness_constraints: reconstruct_terminator_effect from {:#?}", + location + ); + self.flow_inits.reconstruct_terminator_effect(location); + } else { + debug!( + "add_liveness_constraints: reconstruct_statement_effect from {:#?}", + location + ); + self.flow_inits.reconstruct_statement_effect(location); + } + self.flow_inits.apply_local_effect(location); + } + } + + /// Some variable with type `live_ty` is "regular live" at + /// `location` -- i.e., it may be used later. This means that all + /// regions appearing in the type `live_ty` must be live at + /// `location`. + fn push_type_live_constraint(&mut self, value: T, location: Location) + where + T: TypeFoldable<'tcx>, + { + debug!( + "push_type_live_constraint(live_ty={:?}, location={:?})", + value, + location + ); + + self.tcx.for_each_free_region(&value, |live_region| { + self.cx + .constraints + .liveness_set + .push((live_region, location)); + }); + } + + /// Some variable with type `live_ty` is "drop live" at `location` + /// -- i.e., it may be dropped later. This means that *some* of + /// the regions in its type must be live at `location`. The + /// precise set will depend on the dropck constraints, and in + /// particular this takes `#[may_dangle]` into account. + fn add_drop_live_constraint(&mut self, dropped_ty: Ty<'tcx>, location: Location) { + debug!( + "add_drop_live_constraint(dropped_ty={:?}, location={:?})", + dropped_ty, + location + ); + + let tcx = self.cx.infcx.tcx; + let mut types = vec![(dropped_ty, 0)]; + let mut known = FxHashSet(); + while let Some((ty, depth)) = types.pop() { + let span = DUMMY_SP; // FIXME + let result = match tcx.dtorck_constraint_for_ty(span, dropped_ty, depth, ty) { + Ok(result) => result, + Err(ErrorReported) => { + continue; + } + }; + + let ty::DtorckConstraint { + outlives, + dtorck_types, + } = result; + + // All things in the `outlives` array may be touched by + // the destructor and must be live at this point. + for outlive in outlives { + self.push_type_live_constraint(outlive, location); + } + + // However, there may also be some types that + // `dtorck_constraint_for_ty` could not resolve (e.g., + // associated types and parameters). We need to normalize + // associated types here and possibly recursively process. + for ty in dtorck_types { + let ty = self.cx.normalize(&ty, location); + match ty.sty { + ty::TyParam(..) | ty::TyProjection(..) | ty::TyAnon(..) => { + self.push_type_live_constraint(ty, location); + } + + _ => if known.insert(ty) { + types.push((ty, depth + 1)); + }, + } + } + } + } +} 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 fae911780a1..8f18105600a 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -12,6 +12,9 @@ #![allow(unreachable_code)] use borrow_check::nll::region_infer::ClosureRegionRequirementsExt; +use dataflow::FlowAtLocation; +use dataflow::MaybeInitializedLvals; +use dataflow::move_paths::MoveData; use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult}; use rustc::infer::region_constraints::RegionConstraintData; use rustc::traits::{self, FulfillmentContext}; @@ -26,22 +29,43 @@ use std::fmt; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; use transform::{MirPass, MirSource}; +use util::liveness::LivenessResults; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::Idx; +mod liveness; + /// Type checks the given `mir` in the context of the inference /// context `infcx`. Returns any region constraints that have yet to -/// be proven. +/// be proven. This result is includes liveness constraints that +/// ensure that regions appearing in the types of all local variables +/// are live at all points where that local variable may later be +/// used. /// /// 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. -pub fn type_check<'a, 'gcx, 'tcx>( - infcx: &InferCtxt<'a, 'gcx, 'tcx>, +pub(crate) fn type_check<'gcx, 'tcx>( + infcx: &InferCtxt<'_, 'gcx, 'tcx>, + body_id: ast::NodeId, + param_env: ty::ParamEnv<'gcx>, + mir: &Mir<'tcx>, + liveness: &LivenessResults, + flow_inits: &mut FlowAtLocation>, + move_data: &MoveData<'tcx>, +) -> MirTypeckRegionConstraints<'tcx> { + type_check_internal(infcx, body_id, param_env, mir, &mut |cx| { + liveness::generate(cx, mir, liveness, flow_inits, move_data) + }) +} + +fn type_check_internal<'gcx, 'tcx>( + infcx: &InferCtxt<'_, 'gcx, 'tcx>, body_id: ast::NodeId, param_env: ty::ParamEnv<'gcx>, mir: &Mir<'tcx>, + extra: &mut FnMut(&mut TypeChecker<'_, 'gcx, 'tcx>), ) -> MirTypeckRegionConstraints<'tcx> { let mut checker = TypeChecker::new(infcx, body_id, param_env); let errors_reported = { @@ -55,9 +79,12 @@ pub fn type_check<'a, 'gcx, 'tcx>( checker.typeck_mir(mir); } + extra(&mut checker); + checker.constraints } + fn mirbug(tcx: TyCtxt, span: Span, msg: &str) { // We sometimes see MIR failures (notably predicate failures) due to // the fact that we check rvalue sized predicates here. So use `delay_span_bug` @@ -503,7 +530,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { /// constraints needed for it to be valid and well-typed. Along the /// way, it accrues region constraints -- these can later be used by /// NLL region checking. -pub struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { +struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'gcx>, last_span: Span, @@ -1474,7 +1501,7 @@ impl MirPass for TypeckMir { } let param_env = tcx.param_env(def_id); tcx.infer_ctxt().enter(|infcx| { - let _region_constraint_sets = type_check(&infcx, id, param_env, mir); + let _ = type_check_internal(&infcx, id, param_env, mir, &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-fn.rs b/src/test/ui/nll/ty-outlives/projection-fn.rs new file mode 100644 index 00000000000..677d1352788 --- /dev/null +++ b/src/test/ui/nll/ty-outlives/projection-fn.rs @@ -0,0 +1,53 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-Znll -Zborrowck=mir + +#![allow(warnings)] +#![feature(dyn_trait)] + +trait Anything { } + +impl Anything for T { } + +fn no_region<'a, T>(mut x: T) -> Box +where + T: Iterator, +{ + Box::new(x.next()) + //~^ WARNING not reporting region error due to -Znll + //~| ERROR failed type test +} + +fn correct_region<'a, T>(mut x: T) -> Box +where + T: 'a + Iterator, +{ + Box::new(x.next()) +} + +fn wrong_region<'a, 'b, T>(mut x: T) -> Box +where + T: 'b + Iterator, +{ + Box::new(x.next()) + //~^ WARNING not reporting region error due to -Znll + //~| ERROR failed type test +} + +fn outlives_region<'a, 'b, T>(mut x: T) -> Box +where + T: 'b + Iterator, + 'b: 'a, +{ + Box::new(x.next()) +} + +fn main() {} diff --git a/src/test/ui/nll/ty-outlives/projection-fn.stderr b/src/test/ui/nll/ty-outlives/projection-fn.stderr new file mode 100644 index 00000000000..a478348edc1 --- /dev/null +++ b/src/test/ui/nll/ty-outlives/projection-fn.stderr @@ -0,0 +1,26 @@ +warning: not reporting region error due to -Znll + --> $DIR/projection-fn.rs:24:5 + | +24 | Box::new(x.next()) + | ^^^^^^^^^^^^^^^^^^ + +warning: not reporting region error due to -Znll + --> $DIR/projection-fn.rs:40:5 + | +40 | Box::new(x.next()) + | ^^^^^^^^^^^^^^^^^^ + +error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1695 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#3r, point: bb5[0], span: $DIR/projection-fn.rs:24:5: 24:23, test: IsOutlivedByAnyRegionIn([]) } + --> $DIR/projection-fn.rs:24:5 + | +24 | Box::new(x.next()) + | ^^^^^^^^^^^^^^^^^^ + +error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1695 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#4r, point: bb5[0], span: $DIR/projection-fn.rs:40:5: 40:23, test: IsOutlivedByAnyRegionIn(['_#2r]) } + --> $DIR/projection-fn.rs:40:5 + | +40 | Box::new(x.next()) + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From c7cfa2367b0ad4aed16dff7ad3d8d3e9eea6540a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 4 Dec 2017 05:40:43 -0500 Subject: thread through an implicit region body of the fn body --- src/librustc_mir/borrow_check/nll/mod.rs | 2 ++ .../borrow_check/nll/region_infer/mod.rs | 4 ++- .../borrow_check/nll/type_check/mod.rs | 28 +++++++++++---- .../borrow_check/nll/universal_regions.rs | 15 ++++++-- src/test/mir-opt/nll/named-lifetimes-basic.rs | 10 +++--- src/test/mir-opt/nll/reborrow-basic.rs | 8 ++--- src/test/mir-opt/nll/region-liveness-basic.rs | 8 ++--- .../mir-opt/nll/region-liveness-drop-may-dangle.rs | 4 ++- .../nll/region-liveness-drop-no-may-dangle.rs | 4 ++- .../nll/region-liveness-two-disjoint-uses.rs | 12 +++---- src/test/mir-opt/nll/region-subtyping-basic.rs | 12 +++---- src/test/ui/nll/capture-ref-in-struct.stderr | 2 +- .../closure-requirements/escape-argument.stderr | 2 +- .../escape-upvar-nested.stderr | 2 +- .../closure-requirements/escape-upvar-ref.stderr | 2 +- ...shorter-to-static-comparing-against-free.stderr | 2 +- src/test/ui/nll/ty-outlives/projection-fn.stderr | 4 +-- src/test/ui/nll/ty-outlives/ty-param-fn-body.rs | 41 ++++++++++++++++++++++ .../ui/nll/ty-outlives/ty-param-fn-body.stderr | 14 ++++++++ src/test/ui/nll/ty-outlives/ty-param-fn.stderr | 4 +-- 20 files changed, 135 insertions(+), 45 deletions(-) create mode 100644 src/test/ui/nll/ty-outlives/ty-param-fn-body.rs create mode 100644 src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr (limited to 'src/test') diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 3329448e2b7..9e7c94cd7ff 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -78,11 +78,13 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( // 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 fr_fn_body = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body)); let constraint_sets = &type_check::type_check( infcx, mir_node_id, param_env, mir, + fr_fn_body, &liveness, flow_inits, move_data, 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 efa0734b016..4759185d226 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -439,6 +439,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// have no evidence that `'b` outlives `'a`, so we want to report /// an error. fn check_type_tests(&self, infcx: &InferCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) { + let tcx = infcx.tcx; + for type_test in &self.type_tests { debug!("check_type_test: {:?}", type_test); @@ -452,7 +454,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // Oh the humanity. Obviously we will do better than this error eventually. - infcx.tcx.sess.span_err( + tcx.sess.span_err( type_test.span, &format!("failed type test: {:?}", type_test), ); 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 8f18105600a..f7493f653e0 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -51,13 +51,19 @@ pub(crate) fn type_check<'gcx, 'tcx>( body_id: ast::NodeId, param_env: ty::ParamEnv<'gcx>, mir: &Mir<'tcx>, + implicit_region_bound: ty::Region<'tcx>, liveness: &LivenessResults, flow_inits: &mut FlowAtLocation>, move_data: &MoveData<'tcx>, ) -> MirTypeckRegionConstraints<'tcx> { - type_check_internal(infcx, body_id, param_env, mir, &mut |cx| { - liveness::generate(cx, mir, liveness, flow_inits, move_data) - }) + type_check_internal( + infcx, + body_id, + param_env, + mir, + Some(implicit_region_bound), + &mut |cx| liveness::generate(cx, mir, liveness, flow_inits, move_data), + ) } fn type_check_internal<'gcx, 'tcx>( @@ -65,9 +71,10 @@ fn type_check_internal<'gcx, 'tcx>( body_id: ast::NodeId, param_env: ty::ParamEnv<'gcx>, mir: &Mir<'tcx>, + implicit_region_bound: Option>, extra: &mut FnMut(&mut TypeChecker<'_, 'gcx, 'tcx>), ) -> MirTypeckRegionConstraints<'tcx> { - let mut checker = TypeChecker::new(infcx, body_id, param_env); + let mut checker = TypeChecker::new(infcx, body_id, param_env, implicit_region_bound); let errors_reported = { let mut verifier = TypeVerifier::new(&mut checker, mir); verifier.visit_mir(mir); @@ -535,6 +542,7 @@ struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { param_env: ty::ParamEnv<'gcx>, last_span: Span, body_id: ast::NodeId, + implicit_region_bound: Option>, reported_errors: FxHashSet<(Ty<'tcx>, Span)>, constraints: MirTypeckRegionConstraints<'tcx>, } @@ -588,12 +596,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, body_id: ast::NodeId, param_env: ty::ParamEnv<'gcx>, + implicit_region_bound: Option>, ) -> Self { TypeChecker { infcx, last_span: DUMMY_SP, body_id, param_env, + implicit_region_bound, reported_errors: FxHashSet(), constraints: MirTypeckRegionConstraints::default(), } @@ -618,8 +628,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { span_mirbug!(self, "", "errors selecting obligation: {:?}", e); } - self.infcx - .process_registered_region_obligations(&[], None, self.param_env, self.body_id); + self.infcx.process_registered_region_obligations( + &[], + self.implicit_region_bound, + self.param_env, + self.body_id, + ); let data = self.infcx.take_and_reset_region_constraints(); if !data.is_empty() { @@ -1501,7 +1515,7 @@ impl MirPass for TypeckMir { } let param_env = tcx.param_env(def_id); tcx.infer_ctxt().enter(|infcx| { - let _ = type_check_internal(&infcx, id, param_env, mir, &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/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs index 5336bd271f5..ce931a68a0c 100644 --- a/src/librustc_mir/borrow_check/nll/universal_regions.rs +++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs @@ -45,6 +45,11 @@ pub struct UniversalRegions<'tcx> { /// The vid assigned to `'static` pub fr_static: RegionVid, + /// A special region vid created to represent the current MIR fn + /// body. It will outlive the entire CFG but it will not outlive + /// any other universal regions. + pub fr_fn_body: RegionVid, + /// We create region variables such that they are ordered by their /// `RegionClassification`. The first block are globals, then /// externals, then locals. So things from: @@ -408,6 +413,7 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { let first_local_index = self.infcx.num_region_vars(); let inputs_and_output = self.infcx .replace_bound_regions_with_nll_infer_vars(FR, &bound_inputs_and_output); + let fr_fn_body = self.infcx.next_nll_region_var(FR).to_region_vid(); let num_universals = self.infcx.num_region_vars(); // Insert the facts we know from the predicates. Why? Why not. @@ -419,12 +425,16 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { self.add_implied_bounds(&indices, ty); } - // Finally, outlives is reflexive, and static outlives every - // other free region. + // Finally: + // - outlives is reflexive, so `'r: 'r` for every region `'r` + // - `'static: 'r` for every region `'r` + // - `'r: 'fn_body` for every (other) universally quantified + // region `'r`, all of which are provided by our caller for fr in (FIRST_GLOBAL_INDEX..num_universals).map(RegionVid::new) { debug!("build: relating free region {:?} to itself and to 'static", fr); self.relations.relate_universal_regions(fr, fr); self.relations.relate_universal_regions(fr_static, fr); + self.relations.relate_universal_regions(fr, fr_fn_body); } let (output_ty, input_tys) = inputs_and_output.split_last().unwrap(); @@ -445,6 +455,7 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { UniversalRegions { indices, fr_static, + fr_fn_body, first_extern_index, first_local_index, num_universals, diff --git a/src/test/mir-opt/nll/named-lifetimes-basic.rs b/src/test/mir-opt/nll/named-lifetimes-basic.rs index f3a57c08840..71304f71b61 100644 --- a/src/test/mir-opt/nll/named-lifetimes-basic.rs +++ b/src/test/mir-opt/nll/named-lifetimes-basic.rs @@ -27,16 +27,18 @@ fn main() { // END RUST SOURCE // START rustc.use_x.nll.0.mir // | Free Region Mapping -// | '_#0r | Global | ['_#2r, '_#1r, '_#0r, '_#3r] -// | '_#1r | External | ['_#1r] -// | '_#2r | External | ['_#2r, '_#1r] -// | '_#3r | Local | ['_#3r] +// | '_#0r | Global | ['_#2r, '_#1r, '_#0r, '_#4r, '_#3r] +// | '_#1r | External | ['_#1r, '_#4r] +// | '_#2r | External | ['_#2r, '_#1r, '_#4r] +// | '_#3r | Local | ['_#4r, '_#3r] +// | '_#4r | Local | ['_#4r] // | // | Inferred Region Values // | '_#0r | {'_#0r, bb0[0], bb0[1]} // | '_#1r | {'_#1r, bb0[0], bb0[1]} // | '_#2r | {'_#2r, bb0[0], bb0[1]} // | '_#3r | {'_#3r, bb0[0], bb0[1]} +// | '_#4r | {'_#4r, bb0[0], bb0[1]} // | // ... // fn use_x(_1: &'_#1r mut i32, _2: &'_#2r u32, _3: &'_#1r u32, _4: &'_#3r u32) -> bool { diff --git a/src/test/mir-opt/nll/reborrow-basic.rs b/src/test/mir-opt/nll/reborrow-basic.rs index d203472f20c..9e6d6aaee15 100644 --- a/src/test/mir-opt/nll/reborrow-basic.rs +++ b/src/test/mir-opt/nll/reborrow-basic.rs @@ -28,11 +28,11 @@ fn main() { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#6r | {bb0[6], bb0[7], bb0[8], bb0[9], bb0[10], bb0[11], bb0[12], bb0[13], bb0[14]} +// | '_#7r | {bb0[6], bb0[7], bb0[8], bb0[9], bb0[10], bb0[11], bb0[12], bb0[13], bb0[14]} // ... -// | '_#8r | {bb0[11], bb0[12], bb0[13], bb0[14]} +// | '_#9r | {bb0[11], bb0[12], bb0[13], bb0[14]} // ... -// let _2: &'_#6r mut i32; +// let _2: &'_#7r mut i32; // ... -// let _4: &'_#8r mut i32; +// let _4: &'_#9r mut i32; // END rustc.main.nll.0.mir diff --git a/src/test/mir-opt/nll/region-liveness-basic.rs b/src/test/mir-opt/nll/region-liveness-basic.rs index c04cedbc04b..ab99d79d7f3 100644 --- a/src/test/mir-opt/nll/region-liveness-basic.rs +++ b/src/test/mir-opt/nll/region-liveness-basic.rs @@ -31,15 +31,15 @@ fn main() { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#1r | {bb2[0], bb2[1], bb3[0], bb3[1]} -// | '_#2r | {bb2[1], bb3[0], bb3[1]} +// | '_#2r | {bb2[0], bb2[1], bb3[0], bb3[1]} +// | '_#3r | {bb2[1], bb3[0], bb3[1]} // ... -// let _2: &'_#2r usize; +// let _2: &'_#3r usize; // END rustc.main.nll.0.mir // START rustc.main.nll.0.mir // bb2: { // | Live variables on entry to bb2[0]: [_1, _3] -// _2 = &'_#1r _1[_3]; +// _2 = &'_#2r _1[_3]; // | Live variables on entry to bb2[1]: [_2] // switchInt(const true) -> [0u8: bb4, otherwise: bb3]; // } diff --git a/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs b/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs index e2ad49a4436..515772a9427 100644 --- a/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs +++ b/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs @@ -44,5 +44,7 @@ unsafe impl<#[may_dangle] T> Drop for Wrap { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#5r | {bb2[3], bb2[4], bb2[5], bb3[0], bb3[1]} +// | '_#6r | {bb2[3], bb2[4], bb2[5], bb3[0], bb3[1]} +// ... +// let _2: Wrap<&'_#6r usize>; // END rustc.main.nll.0.mir diff --git a/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs b/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs index e0272a51d03..a257910b0b8 100644 --- a/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs +++ b/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs @@ -46,5 +46,7 @@ impl Drop for Wrap { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#5r | {bb2[3], bb2[4], bb2[5], bb3[0], bb3[1], bb3[2], bb4[0], bb5[0], bb5[1], bb5[2], bb6[0], bb7[0], bb7[1], bb8[0]} +// | '_#6r | {bb2[3], bb2[4], bb2[5], bb3[0], bb3[1], bb3[2], bb4[0], bb5[0], bb5[1], bb5[2], bb6[0], bb7[0], bb7[1], bb8[0]} +// ... +// let _2: Wrap<&'_#6r usize>; // END rustc.main.nll.0.mir diff --git a/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs b/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs index 8aa0eb1a3a9..3041c2cb061 100644 --- a/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs +++ b/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs @@ -36,14 +36,14 @@ fn main() { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#1r | {bb2[0], bb2[1], bb3[0], bb3[1]} +// | '_#2r | {bb2[0], bb2[1], bb3[0], bb3[1]} // ... -// | '_#3r | {bb8[1], bb8[2], bb8[3], bb8[4]} -// | '_#4r | {bb2[1], bb3[0], bb3[1], bb8[2], bb8[3], bb8[4]} +// | '_#4r | {bb8[1], bb8[2], bb8[3], bb8[4]} +// | '_#5r | {bb2[1], bb3[0], bb3[1], bb8[2], bb8[3], bb8[4]} // ... -// let mut _2: &'_#4r usize; +// let mut _2: &'_#5r usize; // ... -// _2 = &'_#1r _1[_3]; +// _2 = &'_#2r _1[_3]; // ... -// _2 = &'_#3r (*_10); +// _2 = &'_#4r (*_10); // END rustc.main.nll.0.mir diff --git a/src/test/mir-opt/nll/region-subtyping-basic.rs b/src/test/mir-opt/nll/region-subtyping-basic.rs index 2bc165bd3c4..5a3f831331c 100644 --- a/src/test/mir-opt/nll/region-subtyping-basic.rs +++ b/src/test/mir-opt/nll/region-subtyping-basic.rs @@ -32,16 +32,16 @@ fn main() { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#1r | {bb2[0], bb2[1], bb2[2], bb2[3], bb2[4], bb2[5], bb2[6], bb3[0], bb3[1]} -// | '_#2r | {bb2[1], bb2[2], bb2[3], bb2[4], bb2[5], bb2[6], bb3[0], bb3[1]} -// | '_#3r | {bb2[5], bb2[6], bb3[0], bb3[1]} +// | '_#2r | {bb2[0], bb2[1], bb2[2], bb2[3], bb2[4], bb2[5], bb2[6], bb3[0], bb3[1]} +// | '_#3r | {bb2[1], bb2[2], bb2[3], bb2[4], bb2[5], bb2[6], bb3[0], bb3[1]} +// | '_#4r | {bb2[5], bb2[6], bb3[0], bb3[1]} // END rustc.main.nll.0.mir // START rustc.main.nll.0.mir -// let _2: &'_#2r usize; +// let _2: &'_#3r usize; // ... -// let _6: &'_#3r usize; +// let _6: &'_#4r usize; // ... -// _2 = &'_#1r _1[_3]; +// _2 = &'_#2r _1[_3]; // ... // _7 = _2; // ... diff --git a/src/test/ui/nll/capture-ref-in-struct.stderr b/src/test/ui/nll/capture-ref-in-struct.stderr index 6b57f91987b..9f62b2a41c5 100644 --- a/src/test/ui/nll/capture-ref-in-struct.stderr +++ b/src/test/ui/nll/capture-ref-in-struct.stderr @@ -7,7 +7,7 @@ error[E0597]: `y` does not live long enough 37 | } | - borrowed value only lives until here | - = note: borrowed value must be valid for lifetime '_#4r... + = note: borrowed value must be valid for lifetime '_#5r... error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr index 567ed299ac1..2b0e3661376 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr @@ -32,7 +32,7 @@ error[E0597]: `y` does not live long enough 39 | } | - borrowed value only lives until here | - = note: borrowed value must be valid for lifetime '_#5r... + = note: borrowed value must be valid for lifetime '_#6r... error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr index 6c70afa0c9c..ddda72c5686 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr @@ -59,7 +59,7 @@ error[E0597]: `y` does not live long enough 36 | } | - borrowed value only lives until here | - = note: borrowed value must be valid for lifetime '_#3r... + = note: borrowed value must be valid for lifetime '_#4r... error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr index 0b982dd812b..a0814cfc15f 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr @@ -36,7 +36,7 @@ error[E0597]: `y` does not live long enough 36 | } | - borrowed value only lives until here | - = note: borrowed value must be valid for lifetime '_#3r... + = note: borrowed value must be valid for lifetime '_#4r... error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index 3e54e62d011..c5107322f6f 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -79,7 +79,7 @@ error[E0597]: `a` does not live long enough 49 | } | - borrowed value only lives until here | - = note: borrowed value must be valid for lifetime '_#1r... + = note: borrowed value must be valid for lifetime '_#2r... error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/ty-outlives/projection-fn.stderr b/src/test/ui/nll/ty-outlives/projection-fn.stderr index a478348edc1..77eabef6545 100644 --- a/src/test/ui/nll/ty-outlives/projection-fn.stderr +++ b/src/test/ui/nll/ty-outlives/projection-fn.stderr @@ -10,13 +10,13 @@ warning: not reporting region error due to -Znll 40 | Box::new(x.next()) | ^^^^^^^^^^^^^^^^^^ -error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1695 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#3r, point: bb5[0], span: $DIR/projection-fn.rs:24:5: 24:23, test: IsOutlivedByAnyRegionIn([]) } +error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1695 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#4r, point: bb5[0], span: $DIR/projection-fn.rs:24:5: 24:23, test: IsOutlivedByAnyRegionIn(['_#2r]) } --> $DIR/projection-fn.rs:24:5 | 24 | Box::new(x.next()) | ^^^^^^^^^^^^^^^^^^ -error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1695 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#4r, point: bb5[0], span: $DIR/projection-fn.rs:40:5: 40:23, test: IsOutlivedByAnyRegionIn(['_#2r]) } +error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1695 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#5r, point: bb5[0], span: $DIR/projection-fn.rs:40:5: 40:23, test: IsOutlivedByAnyRegionIn(['_#2r, '_#3r]) } --> $DIR/projection-fn.rs:40:5 | 40 | Box::new(x.next()) diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn-body.rs b/src/test/ui/nll/ty-outlives/ty-param-fn-body.rs new file mode 100644 index 00000000000..42e62b23896 --- /dev/null +++ b/src/test/ui/nll/ty-outlives/ty-param-fn-body.rs @@ -0,0 +1,41 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-Znll -Zborrowck=mir + +// Test that we assume that universal types like `T` outlive the +// function body. + +#![allow(warnings)] +#![feature(dyn_trait)] + +use std::cell::Cell; + +// No errors here, because `'a` is local to the body. +fn region_within_body(t: T) { + let some_int = 22; + let cell = Cell::new(&some_int); + outlives(cell, t) +} + +// Error here, because T: 'a is not satisfied. +fn region_static<'a, T>(cell: Cell<&'a usize>, t: T) { + outlives(cell, t) + //~^ WARNING not reporting region error due to -Znll + //~| ERROR failed type test +} + +fn outlives<'a, T>(x: Cell<&'a usize>, y: T) +where + T: 'a, +{ +} + +fn main() {} diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr b/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr new file mode 100644 index 00000000000..3cc335bb29d --- /dev/null +++ b/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr @@ -0,0 +1,14 @@ +warning: not reporting region error due to -Znll + --> $DIR/ty-param-fn-body.rs:30:5 + | +30 | outlives(cell, t) + | ^^^^^^^^ + +error: failed type test: TypeTest { generic_kind: T/#0, lower_bound: '_#4r, point: bb0[4], span: $DIR/ty-param-fn-body.rs:30:5: 30:22, test: IsOutlivedByAnyRegionIn(['_#2r]) } + --> $DIR/ty-param-fn-body.rs:30:5 + | +30 | outlives(cell, t) + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn.stderr b/src/test/ui/nll/ty-outlives/ty-param-fn.stderr index 5b29ff88621..426bece3e9d 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-fn.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-fn.stderr @@ -10,13 +10,13 @@ warning: not reporting region error due to -Znll 38 | x | ^ -error: failed type test: TypeTest { generic_kind: T/#1, lower_bound: '_#2r, point: bb0[3], span: $DIR/ty-param-fn.rs:22:5: 22:6, test: IsOutlivedByAnyRegionIn([]) } +error: failed type test: TypeTest { generic_kind: T/#1, lower_bound: '_#3r, point: bb0[3], span: $DIR/ty-param-fn.rs:22:5: 22:6, test: IsOutlivedByAnyRegionIn(['_#2r]) } --> $DIR/ty-param-fn.rs:22:5 | 22 | x | ^ -error: failed type test: TypeTest { generic_kind: T/#2, lower_bound: '_#3r, point: bb0[3], span: $DIR/ty-param-fn.rs:38:5: 38:6, test: IsOutlivedByAnyRegionIn(['_#2r]) } +error: failed type test: TypeTest { generic_kind: T/#2, lower_bound: '_#4r, point: bb0[3], span: $DIR/ty-param-fn.rs:38:5: 38:6, test: IsOutlivedByAnyRegionIn(['_#2r, '_#3r]) } --> $DIR/ty-param-fn.rs:38:5 | 38 | x -- cgit 1.4.1-3-g733a5 From 85e1d4749e5ba14ff89073f5812974ec8fdbffd4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 4 Dec 2017 13:04:38 -0500 Subject: propagate type tests from closure to closure creators Currently, we only propagate type tests that exclude all regions from the type. --- .../borrow_check/nll/region_infer/mod.rs | 157 ++++++++++++++--- .../borrow_check/nll/type_check/mod.rs | 1 + .../borrow_check/nll/universal_regions.rs | 43 +++-- .../ty-param-closure-outlives-from-return-type.rs | 66 +++++++ ...-param-closure-outlives-from-return-type.stderr | 58 +++++++ .../ty-param-closure-outlives-from-where-clause.rs | 96 +++++++++++ ...param-closure-outlives-from-where-clause.stderr | 191 +++++++++++++++++++++ 7 files changed, 581 insertions(+), 31 deletions(-) create mode 100644 src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs create mode 100644 src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr create mode 100644 src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs create mode 100644 src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr (limited to 'src/test') 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 4a1eca38bc7..244abb40798 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -12,15 +12,18 @@ use super::universal_regions::UniversalRegions; use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; use rustc::infer::NLLRegionVariableOrigin; +use rustc::infer::RegionObligation; use rustc::infer::RegionVariableOrigin; use rustc::infer::SubregionOrigin; use rustc::infer::region_constraints::{GenericKind, VarOrigins}; use rustc::mir::{ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, Location, Mir}; -use rustc::ty::{self, RegionVid}; +use rustc::traits::ObligationCause; +use rustc::ty::{self, RegionVid, TypeFoldable}; use rustc_data_structures::indexed_vec::IndexVec; use std::fmt; use std::rc::Rc; +use syntax::ast; use syntax_pos::Span; mod annotation; @@ -361,7 +364,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { None }; - self.check_type_tests(infcx, mir); + self.check_type_tests(infcx, mir, outlives_requirements.as_mut()); self.check_universal_regions(infcx, outlives_requirements.as_mut()); @@ -439,21 +442,27 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// therefore add `end('a)` into the region for `'b` -- but we /// have no evidence that `'b` outlives `'a`, so we want to report /// an error. - fn check_type_tests(&self, infcx: &InferCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) { + fn check_type_tests<'gcx>( + &self, + infcx: &InferCtxt<'_, 'gcx, 'tcx>, + mir: &Mir<'tcx>, + mut propagated_outlives_requirements: Option<&mut Vec>>, + ) { let tcx = infcx.tcx; for type_test in &self.type_tests { debug!("check_type_test: {:?}", type_test); - if self.eval_region_test( - mir, - type_test.point, - type_test.lower_bound, - &type_test.test, - ) { + if self.eval_region_test(mir, type_test.point, type_test.lower_bound, &type_test.test) { continue; } + if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements { + if self.try_promote_type_test(infcx, type_test, propagated_outlives_requirements) { + continue; + } + } + // Oh the humanity. Obviously we will do better than this error eventually. tcx.sess.span_err( type_test.span, @@ -462,6 +471,103 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } + fn try_promote_type_test<'gcx>( + &self, + infcx: &InferCtxt<'_, 'gcx, 'tcx>, + type_test: &TypeTest<'tcx>, + propagated_outlives_requirements: &mut Vec>, + ) -> bool { + let tcx = infcx.tcx; + let gcx = tcx.global_tcx(); + + let TypeTest { + generic_kind, + lower_bound, + point: _, + span, + test: _, + } = type_test; + + // TODO. For now, just fail to promote anything with a + // region. This is obviously too strict: we will for example + // fail to promote `>::Bar` to our + // caller. But it is always sound not to promote, that just + // means more errors, and ignoring regions is a convenient + // starting point. This is because we would want to promote to + // a type that references the region-vids of the closure, for + // which we have no global representation just now. + let generic_ty = generic_kind.to_ty(tcx); + if generic_ty.has_free_regions() { + return false; + } + let generic_ty = gcx.lift(&generic_ty).unwrap(); + + // Find some bounding subject-region R+ that is a super-region + // of the existing subject-region R. This should be a non-local, universal + // region, which ensures it can be encoded in a `ClosureOutlivesRequirement`. + let lower_bound_plus = self.promoted_type_test_bound(*lower_bound); + assert!(self.universal_regions.is_universal_region(lower_bound_plus)); + assert!(!self.universal_regions + .is_local_free_region(lower_bound_plus)); + + propagated_outlives_requirements.push(ClosureOutlivesRequirement { + subject: ClosureOutlivesSubject::Ty(generic_ty), + outlived_free_region: lower_bound_plus, + blame_span: *span, + }); + true + } + + /// Here, `lower_bound` (henceforth, `'r`) represents the bound from + /// some type-test `T: 'r`. We are a closure and have found that + /// `T: 'r` is not locally satisfiable, so we want to propagate + /// this constraint to our creator. It is sound for us to do so + /// with some `'r+` known to our creator, where `'r+: 'r`. + /// + /// The tricky bit here: this region `'r` may contain (a) any + /// number of points in the CFG and (b) any number of `end('x)` + /// elements of universally quantified regions. To communicate with + /// our creator, however, we have to pick exactly one universally + /// quantified region -- in other words, exactly one `end('x)` + /// element -- that they understand and which will be `'r+`. + /// + /// We do this as follows: + /// + /// - Ignore the CFG points in `'r`. All universally quantified regions + /// include the CFG anyhow. + /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding + /// a result `'y`. + /// - Finally, we take the non-local upper bound of `'y`. + fn promoted_type_test_bound(&self, lower_bound: RegionVid) -> RegionVid { + let inferred_values = self.inferred_values.as_ref().unwrap(); + + debug!( + "promoted_type_test_bound(lower_bound={:?}={})", + lower_bound, + inferred_values.region_value_str(lower_bound) + ); + + // Find the smallest universal region that contains all other + // universal regions within `region`. + let mut lub = self.universal_regions.fr_fn_body; + for ur in inferred_values.universal_regions_outlived_by(lower_bound) { + lub = self.universal_regions.postdom_upper_bound(lub, ur); + } + + debug!("promoted_type_test_bound: lub={:?}", lub); + + // Grow further to get smallest universal region known to + // creator. + let non_local_lub = self.universal_regions.non_local_upper_bound(lub); + + debug!( + "promoted_type_test_bound: non_local_lub={:?}", + non_local_lub + ); + + non_local_lub + } + /// Test if `test` is true when applied to `lower_bound` at /// `point`, and returns true or false. fn eval_region_test( @@ -487,13 +593,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { .iter() .any(|&r| self.eval_outlives(mir, r, lower_bound, point)), - RegionTest::Any(tests) => tests.iter().any(|test| { - self.eval_region_test(mir, point, lower_bound, test) - }), + RegionTest::Any(tests) => tests + .iter() + .any(|test| self.eval_region_test(mir, point, lower_bound, test)), - RegionTest::All(tests) => tests.iter().all(|test| { - self.eval_region_test(mir, point, lower_bound, test) - }), + RegionTest::All(tests) => tests + .iter() + .all(|test| self.eval_region_test(mir, point, lower_bound, test)), } } @@ -772,17 +878,18 @@ impl fmt::Debug for Constraint { } } -pub trait ClosureRegionRequirementsExt { +pub trait ClosureRegionRequirementsExt<'gcx> { fn apply_requirements<'tcx>( &self, - infcx: &InferCtxt<'_, '_, 'tcx>, + infcx: &InferCtxt<'_, 'gcx, 'tcx>, + body_id: ast::NodeId, location: Location, closure_def_id: DefId, closure_substs: ty::ClosureSubsts<'tcx>, ); } -impl<'gcx> ClosureRegionRequirementsExt for ClosureRegionRequirements<'gcx> { +impl<'gcx> ClosureRegionRequirementsExt<'gcx> for ClosureRegionRequirements<'gcx> { /// Given an instance T of the closure type, this method /// instantiates the "extra" requirements that we computed for the /// closure into the inference context. This has the effect of @@ -797,7 +904,8 @@ impl<'gcx> ClosureRegionRequirementsExt for ClosureRegionRequirements<'gcx> { /// requirements. fn apply_requirements<'tcx>( &self, - infcx: &InferCtxt<'_, '_, 'tcx>, + infcx: &InferCtxt<'_, 'gcx, 'tcx>, + body_id: ast::NodeId, location: Location, closure_def_id: DefId, closure_substs: ty::ClosureSubsts<'tcx>, @@ -843,8 +951,15 @@ impl<'gcx> ClosureRegionRequirementsExt for ClosureRegionRequirements<'gcx> { infcx.sub_regions(origin, outlived_region, region); } - ClosureOutlivesSubject::Ty(_ty) => { - bug!("TODO not yet implemented -- closure outlives subject of a type"); + ClosureOutlivesSubject::Ty(ty) => { + infcx.register_region_obligation( + body_id, + RegionObligation { + sup_type: ty, + sub_region: outlived_region, + cause: ObligationCause::misc(outlives_requirement.blame_span, body_id), + }, + ); } } } 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 f7493f653e0..5c3cdbe2207 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1409,6 +1409,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { if let Some(closure_region_requirements) = tcx.mir_borrowck(*def_id) { closure_region_requirements.apply_requirements( self.infcx, + self.body_id, location, *def_id, *substs, diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs index ce931a68a0c..d3e75626e63 100644 --- a/src/librustc_mir/borrow_check/nll/universal_regions.rs +++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs @@ -267,6 +267,20 @@ impl<'tcx> UniversalRegions<'tcx> { self.num_universals } + /// Given two universal regions, returns the postdominating + /// upper-bound (effectively the least upper bound). + /// + /// (See `TransitiveRelation::postdom_upper_bound` for details on + /// the postdominating upper bound in general.) + pub fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid { + assert!(self.is_universal_region(fr1)); + assert!(self.is_universal_region(fr2)); + *self.relations + .inverse_outlives + .postdom_upper_bound(&fr1, &fr2) + .unwrap_or(&self.fr_static) + } + /// Finds an "upper bound" for `fr` that is not local. In other /// words, returns the smallest (*) known region `fr1` that (a) /// outlives `fr` and (b) is not local. This cannot fail, because @@ -431,7 +445,10 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { // - `'r: 'fn_body` for every (other) universally quantified // region `'r`, all of which are provided by our caller for fr in (FIRST_GLOBAL_INDEX..num_universals).map(RegionVid::new) { - debug!("build: relating free region {:?} to itself and to 'static", fr); + debug!( + "build: relating free region {:?} to itself and to 'static", + fr + ); self.relations.relate_universal_regions(fr, fr); self.relations.relate_universal_regions(fr_static, fr); self.relations.relate_universal_regions(fr, fr_fn_body); @@ -442,15 +459,21 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { // we should not have created any more variables assert_eq!(self.infcx.num_region_vars(), num_universals); - debug!("build: global regions = {}..{}", - FIRST_GLOBAL_INDEX, - first_extern_index); - debug!("build: extern regions = {}..{}", - first_extern_index, - first_local_index); - debug!("build: local regions = {}..{}", - first_local_index, - num_universals); + debug!( + "build: global regions = {}..{}", + FIRST_GLOBAL_INDEX, + first_extern_index + ); + debug!( + "build: extern regions = {}..{}", + first_extern_index, + first_local_index + ); + debug!( + "build: local regions = {}..{}", + first_local_index, + num_universals + ); UniversalRegions { indices, diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs new file mode 100644 index 00000000000..6b23c82c771 --- /dev/null +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs @@ -0,0 +1,66 @@ +// 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 or the MIT license +// , 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::fmt::Debug; + +fn with_signature<'a, T, F>(x: Box, op: F) -> Box + where F: FnOnce(Box) -> Box +{ + op(x) +} + +#[rustc_regions] +fn no_region<'a, T>(x: Box) -> Box +where + T: Debug, +{ + // Here, the closure winds up being required to prove that `T: + // 'a`. In principle, it could know that, except that it is + // type-checked in a fully generic way, and hence it winds up with + // a propagated requirement that `T: '_#2`, where `'_#2` appears + // in the return type. The caller makes the mapping from `'_#2` to + // `'a` (and subsequently reports an error). + + with_signature(x, |y| y) + //~^ WARNING not reporting region error due to -Znll + //~| ERROR failed type test +} + +fn correct_region<'a, T>(x: Box) -> Box +where + T: 'a + Debug, +{ + x +} + +fn wrong_region<'a, 'b, T>(x: Box) -> Box +where + T: 'b + Debug, +{ + x + //~^ WARNING not reporting region error due to -Znll + //~| ERROR failed type test +} + +fn outlives_region<'a, 'b, T>(x: Box) -> Box +where + T: 'b + Debug, + 'b: 'a, +{ + x +} + +fn main() {} diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr new file mode 100644 index 00000000000..721896a93ff --- /dev/null +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr @@ -0,0 +1,58 @@ +warning: not reporting region error due to -Znll + --> $DIR/ty-param-closure-outlives-from-return-type.rs:37:27 + | +37 | with_signature(x, |y| y) + | ^ + +warning: not reporting region error due to -Znll + --> $DIR/ty-param-closure-outlives-from-return-type.rs:53:5 + | +53 | x + | ^ + +note: External requirements + --> $DIR/ty-param-closure-outlives-from-return-type.rs:37:23 + | +37 | with_signature(x, |y| y) + | ^^^^^ + | + = note: defining type: DefId(0/1:14 ~ ty_param_closure_outlives_from_return_type[317d]::no_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box + ] + = note: number of external vids: 3 + = note: where T: '_#2r + +error: failed type test: TypeTest { generic_kind: T/#1, lower_bound: '_#4r, point: bb0[5], span: $DIR/ty-param-closure-outlives-from-return-type.rs:37:23: 37:28, test: IsOutlivedByAnyRegionIn(['_#2r]) } + --> $DIR/ty-param-closure-outlives-from-return-type.rs:37:23 + | +37 | with_signature(x, |y| y) + | ^^^^^ + +note: No external requirements + --> $DIR/ty-param-closure-outlives-from-return-type.rs:26:1 + | +26 | / fn no_region<'a, T>(x: Box) -> Box +27 | | where +28 | | T: Debug, +29 | | { +... | +39 | | //~| ERROR failed type test +40 | | } + | |_^ + | + = note: defining type: DefId(0/0:5 ~ ty_param_closure_outlives_from_return_type[317d]::no_region[0]) with substs [ + '_#1r, + T + ] + +error: failed type test: TypeTest { generic_kind: T/#2, lower_bound: '_#4r, point: bb0[3], span: $DIR/ty-param-closure-outlives-from-return-type.rs:53:5: 53:6, test: IsOutlivedByAnyRegionIn(['_#2r, '_#3r]) } + --> $DIR/ty-param-closure-outlives-from-return-type.rs:53:5 + | +53 | x + | ^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs new file mode 100644 index 00000000000..54f7b4fa50d --- /dev/null +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs @@ -0,0 +1,96 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we can propagate `T: 'a` obligations to our caller. See +// `correct_region` for an explanation of how this test is setup; it's +// somewhat intricate. + +// compile-flags:-Znll -Zborrowck=mir -Zverbose + +#![allow(warnings)] +#![feature(dyn_trait)] +#![feature(rustc_attrs)] + +use std::cell::Cell; + +fn with_signature<'a, T, F>(a: Cell<&'a ()>, b: T, op: F) +where + F: FnOnce(Cell<&'a ()>, T), +{ + op(a, b) +} + +fn require<'a, T>(_a: &Cell<&'a ()>, _b: &T) +where + T: 'a, +{ +} + +#[rustc_regions] +fn no_region<'a, T>(a: Cell<&'a ()>, b: T) { + with_signature(a, b, |x, y| { + //~^ ERROR failed type test + // + // See `correct_region`, which explains the point of this + // test. The only difference is that, in the case of this + // function, there is no where clause *anywhere*, and hence we + // get an error (but reported by the closure creator). + require(&x, &y) + //~^ WARNING not reporting region error due to -Znll + }) +} + +#[rustc_regions] +fn correct_region<'a, T>(a: Cell<&'a ()>, b: T) +where + T: 'a, +{ + with_signature(a, b, |x, y| { + // Key point of this test: + // + // The *closure* is being type-checked with all of its free + // regions "universalized". In particular, it does not know + // that `x` has the type `Cell<&'a ()>`, but rather treats it + // as if the type of `x` is `Cell<&'A ()>`, where `'A` is some + // fresh, independent region distinct from the `'a` which + // appears in the environment. The call to `require` here + // forces us then to prove that `T: 'A`, but the closure + // cannot do it on its own. It has to surface this requirement + // to its creator (which knows that `'a == 'A`). + require(&x, &y) + }) +} + +#[rustc_regions] +fn wrong_region<'a, 'b, T>(a: Cell<&'a ()>, b: T) +where + T: 'b, +{ + with_signature(a, b, |x, y| { + //~^ ERROR failed type test + // See `correct_region` + require(&x, &y) + //~^ WARNING not reporting region error due to -Znll + }) +} + +#[rustc_regions] +fn outlives_region<'a, 'b, T>(a: Cell<&'a ()>, b: T) +where + T: 'b, + 'b: 'a, +{ + with_signature(a, b, |x, y| { + // See `correct_region` + require(&x, &y) + }) +} + +fn main() {} diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr new file mode 100644 index 00000000000..748333badce --- /dev/null +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr @@ -0,0 +1,191 @@ +warning: not reporting region error due to -Znll + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:45:9 + | +45 | require(&x, &y) + | ^^^^^^^ + +warning: not reporting region error due to -Znll + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:79:9 + | +79 | require(&x, &y) + | ^^^^^^^ + +note: External requirements + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:38:26 + | +38 | with_signature(a, b, |x, y| { + | __________________________^ +39 | | //~^ ERROR failed type test +40 | | // +41 | | // See `correct_region`, which explains the point of this +... | +46 | | //~^ WARNING not reporting region error due to -Znll +47 | | }) + | |_____^ + | + = note: defining type: DefId(0/1:16 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]::{{closure}}[0]) with closure substs [ + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#1r ()>, T)) + ] + = note: number of external vids: 2 + = note: where T: '_#1r + +note: External requirements + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:55:26 + | +55 | with_signature(a, b, |x, y| { + | __________________________^ +56 | | // Key point of this test: +57 | | // +58 | | // The *closure* is being type-checked with all of its free +... | +67 | | require(&x, &y) +68 | | }) + | |_____^ + | + = note: defining type: DefId(0/1:19 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + = note: number of external vids: 3 + = note: where T: '_#2r + +note: External requirements + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26 + | +76 | with_signature(a, b, |x, y| { + | __________________________^ +77 | | //~^ ERROR failed type test +78 | | // See `correct_region` +79 | | require(&x, &y) +80 | | //~^ WARNING not reporting region error due to -Znll +81 | | }) + | |_____^ + | + = note: defining type: DefId(0/1:23 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + = note: number of external vids: 3 + = note: where T: '_#2r + +note: External requirements + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:90:26 + | +90 | with_signature(a, b, |x, y| { + | __________________________^ +91 | | // See `correct_region` +92 | | require(&x, &y) +93 | | }) + | |_____^ + | + = note: defining type: DefId(0/1:27 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where T: '_#3r + +error: failed type test: TypeTest { generic_kind: T/#0, lower_bound: '_#3r, point: bb0[5], span: $DIR/ty-param-closure-outlives-from-where-clause.rs:38:26: 47:6, test: IsOutlivedByAnyRegionIn(['_#2r]) } + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:38:26 + | +38 | with_signature(a, b, |x, y| { + | __________________________^ +39 | | //~^ ERROR failed type test +40 | | // +41 | | // See `correct_region`, which explains the point of this +... | +46 | | //~^ WARNING not reporting region error due to -Znll +47 | | }) + | |_____^ + +note: No external requirements + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:37:1 + | +37 | / fn no_region<'a, T>(a: Cell<&'a ()>, b: T) { +38 | | with_signature(a, b, |x, y| { +39 | | //~^ ERROR failed type test +40 | | // +... | +47 | | }) +48 | | } + | |_^ + | + = note: defining type: DefId(0/0:6 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]) with substs [ + T + ] + +note: No external requirements + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:51:1 + | +51 | / fn correct_region<'a, T>(a: Cell<&'a ()>, b: T) +52 | | where +53 | | T: 'a, +54 | | { +... | +68 | | }) +69 | | } + | |_^ + | + = note: defining type: DefId(0/0:7 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]) with substs [ + '_#1r, + T + ] + +error: failed type test: TypeTest { generic_kind: T/#1, lower_bound: '_#5r, point: bb0[5], span: $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26: 81:6, test: IsOutlivedByAnyRegionIn(['_#1r, '_#3r]) } + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26 + | +76 | with_signature(a, b, |x, y| { + | __________________________^ +77 | | //~^ ERROR failed type test +78 | | // See `correct_region` +79 | | require(&x, &y) +80 | | //~^ WARNING not reporting region error due to -Znll +81 | | }) + | |_____^ + +note: No external requirements + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:72:1 + | +72 | / fn wrong_region<'a, 'b, T>(a: Cell<&'a ()>, b: T) +73 | | where +74 | | T: 'b, +75 | | { +... | +81 | | }) +82 | | } + | |_^ + | + = note: defining type: DefId(0/0:8 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]) with substs [ + '_#1r, + T + ] + +note: No external requirements + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:85:1 + | +85 | / fn outlives_region<'a, 'b, T>(a: Cell<&'a ()>, b: T) +86 | | where +87 | | T: 'b, +88 | | 'b: 'a, +... | +93 | | }) +94 | | } + | |_^ + | + = note: defining type: DefId(0/0:9 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]) with substs [ + '_#1r, + '_#2r, + T + ] + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 3fcb13ae458ce6e2eedd34461b4e43c7be31b6b1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 5 Dec 2017 13:15:23 -0500 Subject: handle projections with regions --- .../borrow_check/nll/region_infer/mod.rs | 279 ++++++++++++------ .../borrow_check/nll/universal_regions.rs | 17 +- src/test/ui/nll/ty-outlives/projection-fn.rs | 53 ---- src/test/ui/nll/ty-outlives/projection-fn.stderr | 26 -- .../ty-outlives/projection-no-regions-closure.rs | 68 +++++ .../projection-no-regions-closure.stderr | 157 ++++++++++ .../ui/nll/ty-outlives/projection-no-regions-fn.rs | 53 ++++ .../ty-outlives/projection-no-regions-fn.stderr | 26 ++ .../ty-outlives/projection-one-region-closure.rs | 106 +++++++ .../projection-one-region-closure.stderr | 194 ++++++++++++ .../projection-one-region-trait-bound-closure.rs | 106 +++++++ ...rojection-one-region-trait-bound-closure.stderr | 204 +++++++++++++ ...ection-one-region-trait-bound-static-closure.rs | 99 +++++++ ...on-one-region-trait-bound-static-closure.stderr | 155 ++++++++++ .../projection-two-region-trait-bound-closure.rs | 135 +++++++++ ...rojection-two-region-trait-bound-closure.stderr | 326 +++++++++++++++++++++ 16 files changed, 1830 insertions(+), 174 deletions(-) delete mode 100644 src/test/ui/nll/ty-outlives/projection-fn.rs delete mode 100644 src/test/ui/nll/ty-outlives/projection-fn.stderr create mode 100644 src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs create mode 100644 src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr create mode 100644 src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs create mode 100644 src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr create mode 100644 src/test/ui/nll/ty-outlives/projection-one-region-closure.rs create mode 100644 src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr create mode 100644 src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs create mode 100644 src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr create mode 100644 src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs create mode 100644 src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr create mode 100644 src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs create mode 100644 src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr (limited to 'src/test') 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 244abb40798..f03e8bd7ac1 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -19,7 +19,7 @@ use rustc::infer::region_constraints::{GenericKind, VarOrigins}; use rustc::mir::{ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, Location, Mir}; use rustc::traits::ObligationCause; -use rustc::ty::{self, RegionVid, TypeFoldable}; +use rustc::ty::{self, RegionVid, Ty, TypeFoldable}; use rustc_data_structures::indexed_vec::IndexVec; use std::fmt; use std::rc::Rc; @@ -478,7 +478,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { propagated_outlives_requirements: &mut Vec>, ) -> bool { let tcx = infcx.tcx; - let gcx = tcx.global_tcx(); let TypeTest { generic_kind, @@ -488,80 +487,158 @@ impl<'tcx> RegionInferenceContext<'tcx> { test: _, } = type_test; - // TODO. For now, just fail to promote anything with a - // region. This is obviously too strict: we will for example - // fail to promote `>::Bar` to our - // caller. But it is always sound not to promote, that just - // means more errors, and ignoring regions is a convenient - // starting point. This is because we would want to promote to - // a type that references the region-vids of the closure, for - // which we have no global representation just now. let generic_ty = generic_kind.to_ty(tcx); - if generic_ty.has_free_regions() { - return false; - } - let generic_ty = gcx.lift(&generic_ty).unwrap(); + let subject = match self.try_promote_type_test_subject(infcx, generic_ty) { + Some(s) => s, + None => return false, + }; // Find some bounding subject-region R+ that is a super-region // of the existing subject-region R. This should be a non-local, universal // region, which ensures it can be encoded in a `ClosureOutlivesRequirement`. - let lower_bound_plus = self.promoted_type_test_bound(*lower_bound); + let lower_bound_plus = self.non_local_universal_upper_bound(*lower_bound); assert!(self.universal_regions.is_universal_region(lower_bound_plus)); assert!(!self.universal_regions .is_local_free_region(lower_bound_plus)); propagated_outlives_requirements.push(ClosureOutlivesRequirement { - subject: ClosureOutlivesSubject::Ty(generic_ty), + subject, outlived_free_region: lower_bound_plus, blame_span: *span, }); true } - /// Here, `lower_bound` (henceforth, `'r`) represents the bound from - /// some type-test `T: 'r`. We are a closure and have found that - /// `T: 'r` is not locally satisfiable, so we want to propagate - /// this constraint to our creator. It is sound for us to do so - /// with some `'r+` known to our creator, where `'r+: 'r`. + /// When we promote a type test `T: 'r`, we have to convert the + /// type `T` into something we can store in a query result (so + /// something allocated for `'gcx`). This is problematic if `ty` + /// contains regions. During the course of NLL region checking, we + /// will have replaced all of those regions with fresh inference + /// variables. To create a test subject, we want to replace those + /// inference variables with some region from the closure + /// signature -- this is not always possible, so this is a + /// fallible process. Presuming we do find a suitable region, we + /// will represent it with a `ReClosureBound`, which is a + /// `RegionKind` variant that can be allocated in the gcx. + fn try_promote_type_test_subject<'gcx>( + &self, + infcx: &InferCtxt<'_, 'gcx, 'tcx>, + ty: Ty<'tcx>, + ) -> Option> { + let tcx = infcx.tcx; + let gcx = tcx.global_tcx(); + let inferred_values = self.inferred_values + .as_ref() + .expect("region values not yet inferred"); + + debug!("try_promote_type_test_subject(ty = {:?})", ty); + + let ty = tcx.fold_regions(&ty, &mut false, |r, _depth| { + let region_vid = self.to_region_vid(r); + + // The challenge if this. We have some region variable `r` + // whose value is a set of CFG points and universal + // regions. We want to find if that set is *equivalent* to + // any of the named regions found in the closure. + // + // To do so, we compute the + // `non_local_universal_upper_bound`. This will be a + // non-local, universal region that is greater than `r`. + // However, it might not be *contained* within `r`, so + // then we further check whether this bound is contained + // in `r`. If so, we can say that `r` is equivalent to the + // bound. + // + // Let's work through a few examples. For these, imagine + // that we have 3 non-local regions (I'll denote them as + // `'static`, `'a`, and `'b`, though of course in the code + // they would be represented with indices) where: + // + // - `'static: 'a` + // - `'static: 'b` + // + // First, let's assume that `r` is some existential + // variable with an inferred value `{'a, 'static}` (plus + // some CFG nodes). In this case, the non-local upper + // bound is `'static`, since that outlives `'a`. `'static` + // is also a member of `r` and hence we consider `r` + // equivalent to `'static` (and replace it with + // `'static`). + // + // Now let's consider the inferred value `{'a, 'b}`. This + // means `r` is effectively `'a | 'b`. I'm not sure if + // this can come about, actually, but assuming it did, we + // would get a non-local upper bound of `'static`. Since + // `'static` is not contained in `r`, we would fail to + // find an equivalent. + let upper_bound = self.non_local_universal_upper_bound(region_vid); + if inferred_values.contains(region_vid, upper_bound) { + tcx.mk_region(ty::ReClosureBound(upper_bound)) + } else { + // In the case of a failure, use a `ReVar` + // result. This will cause the `lift` later on to + // fail. + r + } + }); + debug!("try_promote_type_test_subject: folded ty = {:?}", ty); + + // `lift` will only fail if we failed to promote some region. + let ty = gcx.lift(&ty)?; + + Some(ClosureOutlivesSubject::Ty(ty)) + } + + /// Given some universal or existential region `r`, finds a + /// non-local, universal region `r+` that outlives `r` at entry to (and + /// exit from) the closure. In the worst case, this will be + /// `'static`. /// - /// The tricky bit here: this region `'r` may contain (a) any - /// number of points in the CFG and (b) any number of `end('x)` - /// elements of universally quantified regions. To communicate with - /// our creator, however, we have to pick exactly one universally - /// quantified region -- in other words, exactly one `end('x)` - /// element -- that they understand and which will be `'r+`. + /// This is used for two purposes. First, if we are propagated + /// some requirement `T: r`, we can use this method to enlarge `r` + /// to something we can encode for our creator (which only knows + /// about non-local, universal regions). It is also used when + /// encoding `T` as part of `try_promote_type_test_subject` (see + /// that fn for details). /// - /// We do this as follows: + /// Since `r` is (potentially) an existential region, it has some + /// value which may include (a) any number of points in the CFG + /// and (b) any number of `end('x)` elements of universally + /// quantified regions. To convert this into a single universal + /// region we do as follows: /// /// - Ignore the CFG points in `'r`. All universally quantified regions /// include the CFG anyhow. /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding /// a result `'y`. /// - Finally, we take the non-local upper bound of `'y`. - fn promoted_type_test_bound(&self, lower_bound: RegionVid) -> RegionVid { + /// - This uses `UniversalRegions::non_local_upper_bound`, which + /// is similar to this method but only works on universal + /// regions). + fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid { let inferred_values = self.inferred_values.as_ref().unwrap(); debug!( - "promoted_type_test_bound(lower_bound={:?}={})", - lower_bound, - inferred_values.region_value_str(lower_bound) + "non_local_universal_upper_bound(r={:?}={})", + r, + inferred_values.region_value_str(r) ); // Find the smallest universal region that contains all other // universal regions within `region`. let mut lub = self.universal_regions.fr_fn_body; - for ur in inferred_values.universal_regions_outlived_by(lower_bound) { + for ur in inferred_values.universal_regions_outlived_by(r) { lub = self.universal_regions.postdom_upper_bound(lub, ur); } - debug!("promoted_type_test_bound: lub={:?}", lub); + debug!("non_local_universal_upper_bound: lub={:?}", lub); // Grow further to get smallest universal region known to // creator. let non_local_lub = self.universal_regions.non_local_upper_bound(lub); debug!( - "promoted_type_test_bound: non_local_lub={:?}", + "non_local_universal_upper_bound: non_local_lub={:?}", non_local_lub ); @@ -680,32 +757,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Go through each of the universal regions `fr` and check that // they did not grow too large, accumulating any requirements // for our caller into the `outlives_requirements` vector. - let mut outlives_requirements = vec![]; for (fr, _) in universal_definitions { - self.check_universal_region(infcx, fr, &mut outlives_requirements); - - // Propagate unsatisfied requirements if possible, else - // report them. - if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements { - propagated_outlives_requirements.extend(outlives_requirements.drain(..)); - } else { - for outlives_requirement in outlives_requirements.drain(..) { - let fr = match outlives_requirement.subject { - ClosureOutlivesSubject::Region(fr) => fr, - _ => span_bug!( - outlives_requirement.blame_span, - "check_universal_region() produced requirement w/ non-region subject" - ), - }; - - self.report_error( - infcx, - fr, - outlives_requirement.outlived_free_region, - outlives_requirement.blame_span, - ); - } - } + self.check_universal_region(infcx, fr, &mut propagated_outlives_requirements); } } @@ -721,7 +774,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, infcx: &InferCtxt<'_, 'gcx, 'tcx>, longer_fr: RegionVid, - propagated_outlives_requirements: &mut Vec>, + propagated_outlives_requirements: &mut Option<&mut Vec>>, ) { let inferred_values = self.inferred_values.as_ref().unwrap(); @@ -743,33 +796,39 @@ impl<'tcx> RegionInferenceContext<'tcx> { let blame_span = self.blame_span(longer_fr, shorter_fr); - // Shrink `fr` until we find a non-local region (if we do). - // We'll call that `fr-` -- it's ever so slightly smaller than `fr`. - if let Some(fr_minus) = self.universal_regions.non_local_lower_bound(longer_fr) { - debug!("check_universal_region: fr_minus={:?}", fr_minus); - - // Grow `shorter_fr` until we find a non-local - // regon. (We always will.) We'll call that - // `shorter_fr+` -- it's ever so slightly larger than - // `fr`. - let shorter_fr_plus = self.universal_regions.non_local_upper_bound(shorter_fr); - debug!( - "check_universal_region: shorter_fr_plus={:?}", - shorter_fr_plus - ); + if let Some(propagated_outlives_requirements) = propagated_outlives_requirements { + // Shrink `fr` until we find a non-local region (if we do). + // We'll call that `fr-` -- it's ever so slightly smaller than `fr`. + if let Some(fr_minus) = self.universal_regions.non_local_lower_bound(longer_fr) { + debug!("check_universal_region: fr_minus={:?}", fr_minus); + + // Grow `shorter_fr` until we find a non-local + // regon. (We always will.) We'll call that + // `shorter_fr+` -- it's ever so slightly larger than + // `fr`. + let shorter_fr_plus = self.universal_regions.non_local_upper_bound(shorter_fr); + debug!( + "check_universal_region: shorter_fr_plus={:?}", + shorter_fr_plus + ); - // Push the constraint `fr-: shorter_fr+` - propagated_outlives_requirements.push(ClosureOutlivesRequirement { - subject: ClosureOutlivesSubject::Region(fr_minus), - outlived_free_region: shorter_fr_plus, - blame_span: blame_span, - }); - return; + // Push the constraint `fr-: shorter_fr+` + propagated_outlives_requirements.push(ClosureOutlivesRequirement { + subject: ClosureOutlivesSubject::Region(fr_minus), + outlived_free_region: shorter_fr_plus, + blame_span: blame_span, + }); + return; + } } - // If we could not shrink `fr` to something smaller that - // the external users care about, then we can't pass the - // buck; just report an error. + // If we are not in a context where we can propagate + // errors, or we could not shrink `fr` to something + // smaller, then just report an error. + // + // Note: in this case, we use the unapproximated regions + // to report the error. This gives better error messages + // in some cases. self.report_error(infcx, longer_fr, shorter_fr, blame_span); } } @@ -878,8 +937,8 @@ impl fmt::Debug for Constraint { } } -pub trait ClosureRegionRequirementsExt<'gcx> { - fn apply_requirements<'tcx>( +pub trait ClosureRegionRequirementsExt<'gcx, 'tcx> { + fn apply_requirements( &self, infcx: &InferCtxt<'_, 'gcx, 'tcx>, body_id: ast::NodeId, @@ -887,9 +946,18 @@ pub trait ClosureRegionRequirementsExt<'gcx> { closure_def_id: DefId, closure_substs: ty::ClosureSubsts<'tcx>, ); + + fn subst_closure_mapping( + &self, + infcx: &InferCtxt<'_, 'gcx, 'tcx>, + closure_mapping: &IndexVec>, + value: &T, + ) -> T + where + T: TypeFoldable<'tcx>; } -impl<'gcx> ClosureRegionRequirementsExt<'gcx> for ClosureRegionRequirements<'gcx> { +impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequirements<'gcx> { /// Given an instance T of the closure type, this method /// instantiates the "extra" requirements that we computed for the /// closure into the inference context. This has the effect of @@ -902,7 +970,7 @@ impl<'gcx> ClosureRegionRequirementsExt<'gcx> for ClosureRegionRequirements<'gcx /// a vector. Then we can just index into that vector to extract /// out the corresponding region from T and apply the /// requirements. - fn apply_requirements<'tcx>( + fn apply_requirements( &self, infcx: &InferCtxt<'_, 'gcx, 'tcx>, body_id: ast::NodeId, @@ -927,7 +995,7 @@ impl<'gcx> ClosureRegionRequirementsExt<'gcx> for ClosureRegionRequirements<'gcx // into a vector. These are the regions that we will be // relating to one another. let closure_mapping = - UniversalRegions::closure_mapping(infcx, user_closure_ty, self.num_external_vids); + &UniversalRegions::closure_mapping(infcx, user_closure_ty, self.num_external_vids); debug!("apply_requirements: closure_mapping={:?}", closure_mapping); // Create the predicates. @@ -943,15 +1011,24 @@ impl<'gcx> ClosureRegionRequirementsExt<'gcx> for ClosureRegionRequirements<'gcx debug!( "apply_requirements: region={:?} \ outlived_region={:?} \ - outlives_requirements={:?}", + outlives_requirement={:?}", region, outlived_region, - outlives_requirement + outlives_requirement, ); infcx.sub_regions(origin, outlived_region, region); } ClosureOutlivesSubject::Ty(ty) => { + let ty = self.subst_closure_mapping(infcx, closure_mapping, &ty); + debug!( + "apply_requirements: ty={:?} \ + outlived_region={:?} \ + outlives_requirement={:?}", + ty, + outlived_region, + outlives_requirement, + ); infcx.register_region_obligation( body_id, RegionObligation { @@ -964,4 +1041,22 @@ impl<'gcx> ClosureRegionRequirementsExt<'gcx> for ClosureRegionRequirements<'gcx } } } + + fn subst_closure_mapping( + &self, + infcx: &InferCtxt<'_, 'gcx, 'tcx>, + closure_mapping: &IndexVec>, + value: &T, + ) -> T + where + T: TypeFoldable<'tcx> + { + infcx.tcx.fold_regions(value, &mut false, |r, _depth| { + if let ty::ReClosureBound(vid) = r { + closure_mapping[*vid] + } else { + bug!("subst_closure_mapping: encountered non-closure bound free region {:?}", r) + } + }) + } } diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs index d3e75626e63..5f4a72542b2 100644 --- a/src/librustc_mir/borrow_check/nll/universal_regions.rs +++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs @@ -247,17 +247,24 @@ impl<'tcx> UniversalRegions<'tcx> { (FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::new) } - /// True if `r` is classied as a global region. + /// True if `r` is classified as a global region. pub fn is_global_free_region(&self, r: RegionVid) -> bool { self.region_classification(r) == Some(RegionClassification::Global) } - /// True if `r` is classied as an external region. + /// True if `r` is classified as an external region. pub fn is_extern_free_region(&self, r: RegionVid) -> bool { self.region_classification(r) == Some(RegionClassification::External) } - /// True if `r` is classied as an local region. + /// True if `r` is a free region that is classified as global or + /// extern. This is an important category, because these regions + /// can be referenced in `ClosureRegionRequirements`. + pub fn is_non_local_free_region(&self, r: RegionVid) -> bool { + self.region_classification(r) == Some(RegionClassification::Local) + } + + /// True if `r` is classified as an local region. pub fn is_local_free_region(&self, r: RegionVid) -> bool { self.region_classification(r) == Some(RegionClassification::Local) } @@ -324,6 +331,10 @@ impl<'tcx> UniversalRegions<'tcx> { relation: &TransitiveRelation, fr0: RegionVid, ) -> Option { + // This method assumes that `fr0` is one of the universally + // quantified region variables. + assert!(self.is_universal_region(fr0)); + let mut external_parents = vec![]; let mut queue = vec![&fr0]; diff --git a/src/test/ui/nll/ty-outlives/projection-fn.rs b/src/test/ui/nll/ty-outlives/projection-fn.rs deleted file mode 100644 index 677d1352788..00000000000 --- a/src/test/ui/nll/ty-outlives/projection-fn.rs +++ /dev/null @@ -1,53 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags:-Znll -Zborrowck=mir - -#![allow(warnings)] -#![feature(dyn_trait)] - -trait Anything { } - -impl Anything for T { } - -fn no_region<'a, T>(mut x: T) -> Box -where - T: Iterator, -{ - Box::new(x.next()) - //~^ WARNING not reporting region error due to -Znll - //~| ERROR failed type test -} - -fn correct_region<'a, T>(mut x: T) -> Box -where - T: 'a + Iterator, -{ - Box::new(x.next()) -} - -fn wrong_region<'a, 'b, T>(mut x: T) -> Box -where - T: 'b + Iterator, -{ - Box::new(x.next()) - //~^ WARNING not reporting region error due to -Znll - //~| ERROR failed type test -} - -fn outlives_region<'a, 'b, T>(mut x: T) -> Box -where - T: 'b + Iterator, - 'b: 'a, -{ - Box::new(x.next()) -} - -fn main() {} diff --git a/src/test/ui/nll/ty-outlives/projection-fn.stderr b/src/test/ui/nll/ty-outlives/projection-fn.stderr deleted file mode 100644 index 77eabef6545..00000000000 --- a/src/test/ui/nll/ty-outlives/projection-fn.stderr +++ /dev/null @@ -1,26 +0,0 @@ -warning: not reporting region error due to -Znll - --> $DIR/projection-fn.rs:24:5 - | -24 | Box::new(x.next()) - | ^^^^^^^^^^^^^^^^^^ - -warning: not reporting region error due to -Znll - --> $DIR/projection-fn.rs:40:5 - | -40 | Box::new(x.next()) - | ^^^^^^^^^^^^^^^^^^ - -error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1695 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#4r, point: bb5[0], span: $DIR/projection-fn.rs:24:5: 24:23, test: IsOutlivedByAnyRegionIn(['_#2r]) } - --> $DIR/projection-fn.rs:24:5 - | -24 | Box::new(x.next()) - | ^^^^^^^^^^^^^^^^^^ - -error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1695 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#5r, point: bb5[0], span: $DIR/projection-fn.rs:40:5: 40:23, test: IsOutlivedByAnyRegionIn(['_#2r, '_#3r]) } - --> $DIR/projection-fn.rs:40:5 - | -40 | Box::new(x.next()) - | ^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs new file mode 100644 index 00000000000..b91c01fb671 --- /dev/null +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs @@ -0,0 +1,68 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-Znll -Zborrowck=mir -Zverbose + +// Tests closures that propagate an outlives relationship to their +// creator where the subject is a projection with no regions (`::Item`, to be exact). + +#![allow(warnings)] +#![feature(dyn_trait)] +#![feature(rustc_attrs)] + +trait Anything { } + +impl Anything for T { } + +fn with_signature<'a, T, F>(x: Box, op: F) -> Box + where F: FnOnce(Box) -> Box +{ + op(x) +} + +#[rustc_regions] +fn no_region<'a, T>(x: Box) -> Box +where + T: Iterator, +{ + with_signature(x, |mut y| Box::new(y.next())) + //~^ WARNING not reporting region error due to -Znll + //~| ERROR failed type test +} + +#[rustc_regions] +fn correct_region<'a, T>(x: Box) -> Box +where + T: 'a + Iterator, +{ + with_signature(x, |mut y| Box::new(y.next())) +} + +#[rustc_regions] +fn wrong_region<'a, 'b, T>(x: Box) -> Box +where + T: 'b + Iterator, +{ + with_signature(x, |mut y| Box::new(y.next())) + //~^ WARNING not reporting region error due to -Znll + //~| ERROR failed type test +} + +#[rustc_regions] +fn outlives_region<'a, 'b, T>(x: Box) -> Box +where + T: 'b + Iterator, + 'b: 'a, +{ + with_signature(x, |mut y| Box::new(y.next())) +} + +fn main() {} diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr new file mode 100644 index 00000000000..1d124f2d49a --- /dev/null +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr @@ -0,0 +1,157 @@ +warning: not reporting region error due to -Znll + --> $DIR/projection-no-regions-closure.rs:36:31 + | +36 | with_signature(x, |mut y| Box::new(y.next())) + | ^^^^^^^^^^^^^^^^^^ + +warning: not reporting region error due to -Znll + --> $DIR/projection-no-regions-closure.rs:54:31 + | +54 | with_signature(x, |mut y| Box::new(y.next())) + | ^^^^^^^^^^^^^^^^^^ + +note: External requirements + --> $DIR/projection-no-regions-closure.rs:36:23 + | +36 | with_signature(x, |mut y| Box::new(y.next())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:15 ~ projection_no_regions_closure[317d]::no_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box + ] + = note: number of external vids: 3 + = note: where ::Item: '_#2r + +note: External requirements + --> $DIR/projection-no-regions-closure.rs:46:23 + | +46 | with_signature(x, |mut y| Box::new(y.next())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:18 ~ projection_no_regions_closure[317d]::correct_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box + ] + = note: number of external vids: 3 + = note: where ::Item: '_#2r + +note: External requirements + --> $DIR/projection-no-regions-closure.rs:54:23 + | +54 | with_signature(x, |mut y| Box::new(y.next())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:22 ~ projection_no_regions_closure[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box + ] + = note: number of external vids: 4 + = note: where ::Item: '_#3r + +note: External requirements + --> $DIR/projection-no-regions-closure.rs:65:23 + | +65 | with_signature(x, |mut y| Box::new(y.next())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:26 ~ projection_no_regions_closure[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box + ] + = note: number of external vids: 4 + = note: where ::Item: '_#3r + +error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1697 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#4r, point: bb0[5], span: $DIR/projection-no-regions-closure.rs:36:23: 36:49, test: IsOutlivedByAnyRegionIn(['_#2r]) } + --> $DIR/projection-no-regions-closure.rs:36:23 + | +36 | with_signature(x, |mut y| Box::new(y.next())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: No external requirements + --> $DIR/projection-no-regions-closure.rs:32:1 + | +32 | / fn no_region<'a, T>(x: Box) -> Box +33 | | where +34 | | T: Iterator, +35 | | { +... | +38 | | //~| ERROR failed type test +39 | | } + | |_^ + | + = note: defining type: DefId(0/0:6 ~ projection_no_regions_closure[317d]::no_region[0]) with substs [ + '_#1r, + T + ] + +note: No external requirements + --> $DIR/projection-no-regions-closure.rs:42:1 + | +42 | / fn correct_region<'a, T>(x: Box) -> Box +43 | | where +44 | | T: 'a + Iterator, +45 | | { +46 | | with_signature(x, |mut y| Box::new(y.next())) +47 | | } + | |_^ + | + = note: defining type: DefId(0/0:7 ~ projection_no_regions_closure[317d]::correct_region[0]) with substs [ + '_#1r, + T + ] + +error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1697 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#6r, point: bb0[5], span: $DIR/projection-no-regions-closure.rs:54:23: 54:49, test: IsOutlivedByAnyRegionIn(['_#2r, '_#3r]) } + --> $DIR/projection-no-regions-closure.rs:54:23 + | +54 | with_signature(x, |mut y| Box::new(y.next())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: No external requirements + --> $DIR/projection-no-regions-closure.rs:50:1 + | +50 | / fn wrong_region<'a, 'b, T>(x: Box) -> Box +51 | | where +52 | | T: 'b + Iterator, +53 | | { +... | +56 | | //~| ERROR failed type test +57 | | } + | |_^ + | + = note: defining type: DefId(0/0:8 ~ projection_no_regions_closure[317d]::wrong_region[0]) with substs [ + '_#1r, + '_#2r, + T + ] + +note: No external requirements + --> $DIR/projection-no-regions-closure.rs:60:1 + | +60 | / fn outlives_region<'a, 'b, T>(x: Box) -> Box +61 | | where +62 | | T: 'b + Iterator, +63 | | 'b: 'a, +64 | | { +65 | | with_signature(x, |mut y| Box::new(y.next())) +66 | | } + | |_^ + | + = note: defining type: DefId(0/0:9 ~ projection_no_regions_closure[317d]::outlives_region[0]) with substs [ + '_#1r, + '_#2r, + T + ] + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs new file mode 100644 index 00000000000..b7822eb259b --- /dev/null +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs @@ -0,0 +1,53 @@ +// 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 or the MIT license +// , 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)] + +trait Anything { } + +impl Anything for T { } + +fn no_region<'a, T>(mut x: T) -> Box +where + T: Iterator, +{ + Box::new(x.next()) + //~^ WARNING not reporting region error due to -Znll + //~| ERROR failed type test +} + +fn correct_region<'a, T>(mut x: T) -> Box +where + T: 'a + Iterator, +{ + Box::new(x.next()) +} + +fn wrong_region<'a, 'b, T>(mut x: T) -> Box +where + T: 'b + Iterator, +{ + Box::new(x.next()) + //~^ WARNING not reporting region error due to -Znll + //~| ERROR failed type test +} + +fn outlives_region<'a, 'b, T>(mut x: T) -> Box +where + T: 'b + Iterator, + 'b: 'a, +{ + Box::new(x.next()) +} + +fn main() {} diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr new file mode 100644 index 00000000000..5c3bd04f3b1 --- /dev/null +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr @@ -0,0 +1,26 @@ +warning: not reporting region error due to -Znll + --> $DIR/projection-no-regions-fn.rs:24:5 + | +24 | Box::new(x.next()) + | ^^^^^^^^^^^^^^^^^^ + +warning: not reporting region error due to -Znll + --> $DIR/projection-no-regions-fn.rs:40:5 + | +40 | Box::new(x.next()) + | ^^^^^^^^^^^^^^^^^^ + +error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1697 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#4r, point: bb5[0], span: $DIR/projection-no-regions-fn.rs:24:5: 24:23, test: IsOutlivedByAnyRegionIn(['_#2r]) } + --> $DIR/projection-no-regions-fn.rs:24:5 + | +24 | Box::new(x.next()) + | ^^^^^^^^^^^^^^^^^^ + +error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1697 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#5r, point: bb5[0], span: $DIR/projection-no-regions-fn.rs:40:5: 40:23, test: IsOutlivedByAnyRegionIn(['_#2r, '_#3r]) } + --> $DIR/projection-no-regions-fn.rs:40:5 + | +40 | Box::new(x.next()) + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs new file mode 100644 index 00000000000..cd9b1c2a8ce --- /dev/null +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs @@ -0,0 +1,106 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test cases where we constrain `>::AssocType` to +// outlive `'a` and there are no bounds in the trait definition of +// `Anything`. This means that the constraint can only be satisfied in two +// ways: +// +// - by ensuring that `T: 'a` and `'b: 'a`, or +// - by something in the where clauses. +// +// As of this writing, the where clause option does not work because +// of limitations in our region inferencing system (this is true both +// with and without NLL). See `projection_outlives`. +// +// Ensuring that both `T: 'a` and `'b: 'a` holds does work (`elements_outlive`). + +// compile-flags:-Znll -Zborrowck=mir -Zverbose + +#![allow(warnings)] +#![feature(dyn_trait)] +#![feature(rustc_attrs)] + +use std::cell::Cell; + +trait Anything<'a> { + type AssocType; +} + +fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F) +where + F: FnOnce(Cell<&'a ()>, T), +{ + op(cell, t) +} + +fn require<'a, 'b, T>(_cell: Cell<&'a ()>, _t: T) +where + T: Anything<'b>, + T::AssocType: 'a, +{ +} + +#[rustc_regions] +fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'b>, +{ + with_signature(cell, t, |cell, t| require(cell, t)); + //~^ WARNING not reporting region error due to -Znll + //~| ERROR failed type test + //~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r` +} + +#[rustc_regions] +fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'b>, + 'a: 'a, +{ + with_signature(cell, t, |cell, t| require(cell, t)); + //~^ WARNING not reporting region error due to -Znll + //~| ERROR failed type test + //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` +} + +#[rustc_regions] +fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'b>, + T::AssocType: 'a, +{ + // This error is unfortunate. This code ought to type-check: we + // are projecting `>::AssocType`, and we know + // that this outlives `'a` because of the where-clause. However, + // the way the region checker works, we don't register this + // outlives obligation, and hence we get an error: this is because + // what we see is a projection like `>::AssocType`, and we don't yet know if `?0` will + // equal `'b` or not, so we ignore the where-clause. Obviously we + // can do better here with a more involved verification step. + + with_signature(cell, t, |cell, t| require(cell, t)); + //~^ WARNING not reporting region error due to -Znll + //~| ERROR failed type test + //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` +} + +#[rustc_regions] +fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'b>, + T: 'a, + 'b: 'a, +{ + with_signature(cell, t, |cell, t| require(cell, t)); +} + +fn main() {} diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr new file mode 100644 index 00000000000..d187a094ec6 --- /dev/null +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -0,0 +1,194 @@ +warning: not reporting region error due to -Znll + --> $DIR/projection-one-region-closure.rs:56:39 + | +56 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^ + +warning: not reporting region error due to -Znll + --> $DIR/projection-one-region-closure.rs:68:39 + | +68 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^ + +warning: not reporting region error due to -Znll + --> $DIR/projection-one-region-closure.rs:90:39 + | +90 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^ + +note: External requirements + --> $DIR/projection-one-region-closure.rs:56:29 + | +56 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:19 ~ projection_one_region_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + = note: number of external vids: 3 + = note: where T: '_#2r + = note: where '_#1r: '_#2r + +note: External requirements + --> $DIR/projection-one-region-closure.rs:68:29 + | +68 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:23 ~ projection_one_region_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where T: '_#3r + = note: where '_#2r: '_#3r + +note: External requirements + --> $DIR/projection-one-region-closure.rs:90:29 + | +90 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:27 ~ projection_one_region_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where T: '_#3r + = note: where '_#2r: '_#3r + +note: External requirements + --> $DIR/projection-one-region-closure.rs:103:29 + | +103 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:31 ~ projection_one_region_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where T: '_#3r + = note: where '_#2r: '_#3r + +error: failed type test: TypeTest { generic_kind: T/#1, lower_bound: '_#5r, point: bb0[5], span: $DIR/projection-one-region-closure.rs:56:29: 56:55, test: IsOutlivedByAnyRegionIn(['_#3r]) } + --> $DIR/projection-one-region-closure.rs:56:29 + | +56 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r` + --> $DIR/projection-one-region-closure.rs:56:20 + | +56 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^ + +note: No external requirements + --> $DIR/projection-one-region-closure.rs:52:1 + | +52 | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +53 | | where +54 | | T: Anything<'b>, +55 | | { +... | +59 | | //~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r` +60 | | } + | |_^ + | + = note: defining type: DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]) with substs [ + '_#1r, + T + ] + +error: failed type test: TypeTest { generic_kind: T/#2, lower_bound: '_#6r, point: bb0[5], span: $DIR/projection-one-region-closure.rs:68:29: 68:55, test: IsOutlivedByAnyRegionIn(['_#3r]) } + --> $DIR/projection-one-region-closure.rs:68:29 + | +68 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` + --> $DIR/projection-one-region-closure.rs:68:20 + | +68 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^ + +note: No external requirements + --> $DIR/projection-one-region-closure.rs:63:1 + | +63 | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +64 | | where +65 | | T: Anything<'b>, +66 | | 'a: 'a, +... | +71 | | //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` +72 | | } + | |_^ + | + = note: defining type: DefId(0/0:9 ~ projection_one_region_closure[317d]::no_relationships_early[0]) with substs [ + '_#1r, + '_#2r, + T + ] + +error: failed type test: TypeTest { generic_kind: T/#2, lower_bound: '_#6r, point: bb0[5], span: $DIR/projection-one-region-closure.rs:90:29: 90:55, test: IsOutlivedByAnyRegionIn(['_#3r]) } + --> $DIR/projection-one-region-closure.rs:90:29 + | +90 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` + --> $DIR/projection-one-region-closure.rs:90:20 + | +90 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^ + +note: No external requirements + --> $DIR/projection-one-region-closure.rs:75:1 + | +75 | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +76 | | where +77 | | T: Anything<'b>, +78 | | T::AssocType: 'a, +... | +93 | | //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` +94 | | } + | |_^ + | + = note: defining type: DefId(0/0:10 ~ projection_one_region_closure[317d]::projection_outlives[0]) with substs [ + '_#1r, + '_#2r, + T + ] + +note: No external requirements + --> $DIR/projection-one-region-closure.rs:97:1 + | +97 | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +98 | | where +99 | | T: Anything<'b>, +100 | | T: 'a, +... | +103 | | with_signature(cell, t, |cell, t| require(cell, t)); +104 | | } + | |_^ + | + = note: defining type: DefId(0/0:11 ~ projection_one_region_closure[317d]::elements_outlive[0]) with substs [ + '_#1r, + '_#2r, + T + ] + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs new file mode 100644 index 00000000000..e179927dfb0 --- /dev/null +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs @@ -0,0 +1,106 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test cases where we constrain `>::AssocType` to +// outlive `'a` and there is a unique bound in the trait definition of +// `Anything` -- i.e., we know that `AssocType` outlives `'b`. In this +// case, the best way to satisfy the trait bound is to show that `'b: +// 'a`, which can be done in various ways. + +// compile-flags:-Znll -Zborrowck=mir -Zverbose + +#![allow(warnings)] +#![feature(dyn_trait)] +#![feature(rustc_attrs)] + +use std::cell::Cell; + +trait Anything<'a> { + type AssocType: 'a; +} + +fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F) +where + F: FnOnce(Cell<&'a ()>, T), +{ + op(cell, t) +} + +fn require<'a, 'b, T>(_cell: Cell<&'a ()>, _t: T) +where + T: Anything<'b>, + T::AssocType: 'a, +{ +} + +#[rustc_regions] +fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'b>, +{ + with_signature(cell, t, |cell, t| require(cell, t)); + //~^ WARNING not reporting region error due to -Znll + //~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r` +} + +#[rustc_regions] +fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'b>, + 'a: 'a, +{ + with_signature(cell, t, |cell, t| require(cell, t)); + //~^ WARNING not reporting region error due to -Znll + //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` +} + +#[rustc_regions] +fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'b>, + T::AssocType: 'a, +{ + // This error is unfortunate. This code ought to type-check: we + // are projecting `>::AssocType`, and we know + // that this outlives `'a` because of the where-clause. However, + // the way the region checker works, we don't register this + // outlives obligation, and hence we get an error: this is because + // what we see is a projection like `>::AssocType`, and we don't yet know if `?0` will + // equal `'b` or not, so we ignore the where-clause. Obviously we + // can do better here with a more involved verification step. + + with_signature(cell, t, |cell, t| require(cell, t)); + //~^ WARNING not reporting region error due to -Znll + //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` +} + +#[rustc_regions] +fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'b>, + 'b: 'a, +{ + with_signature(cell, t, |cell, t| require(cell, t)); +} + +#[rustc_regions] +fn one_region<'a, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'a>, +{ + // Note that in this case the closure still propagates an external + // requirement between two variables in its signature, but the + // creator maps both those two region variables to `'a` on its + // side. + with_signature(cell, t, |cell, t| require(cell, t)); +} + +fn main() {} diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr new file mode 100644 index 00000000000..1088ae846fe --- /dev/null +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr @@ -0,0 +1,204 @@ +warning: not reporting region error due to -Znll + --> $DIR/projection-one-region-trait-bound-closure.rs:48:39 + | +48 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^ + +warning: not reporting region error due to -Znll + --> $DIR/projection-one-region-trait-bound-closure.rs:59:39 + | +59 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^ + +warning: not reporting region error due to -Znll + --> $DIR/projection-one-region-trait-bound-closure.rs:80:39 + | +80 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^ + +note: External requirements + --> $DIR/projection-one-region-trait-bound-closure.rs:48:29 + | +48 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:19 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + = note: number of external vids: 3 + = note: where '_#1r: '_#2r + +note: External requirements + --> $DIR/projection-one-region-trait-bound-closure.rs:59:29 + | +59 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where '_#2r: '_#3r + +note: External requirements + --> $DIR/projection-one-region-trait-bound-closure.rs:80:29 + | +80 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where '_#2r: '_#3r + +note: External requirements + --> $DIR/projection-one-region-trait-bound-closure.rs:91:29 + | +91 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where '_#2r: '_#3r + +note: External requirements + --> $DIR/projection-one-region-trait-bound-closure.rs:103:29 + | +103 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + = note: number of external vids: 3 + = note: where '_#1r: '_#2r + +error: free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r` + --> $DIR/projection-one-region-trait-bound-closure.rs:48:20 + | +48 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^ + +note: No external requirements + --> $DIR/projection-one-region-trait-bound-closure.rs:44:1 + | +44 | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +45 | | where +46 | | T: Anything<'b>, +47 | | { +... | +50 | | //~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r` +51 | | } + | |_^ + | + = note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [ + '_#1r, + T + ] + +error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` + --> $DIR/projection-one-region-trait-bound-closure.rs:59:20 + | +59 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^ + +note: No external requirements + --> $DIR/projection-one-region-trait-bound-closure.rs:54:1 + | +54 | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +55 | | where +56 | | T: Anything<'b>, +57 | | 'a: 'a, +... | +61 | | //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` +62 | | } + | |_^ + | + = note: defining type: DefId(0/0:9 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]) with substs [ + '_#1r, + '_#2r, + T + ] + +error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` + --> $DIR/projection-one-region-trait-bound-closure.rs:80:20 + | +80 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^ + +note: No external requirements + --> $DIR/projection-one-region-trait-bound-closure.rs:65:1 + | +65 | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +66 | | where +67 | | T: Anything<'b>, +68 | | T::AssocType: 'a, +... | +82 | | //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` +83 | | } + | |_^ + | + = note: defining type: DefId(0/0:10 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]) with substs [ + '_#1r, + '_#2r, + T + ] + +note: No external requirements + --> $DIR/projection-one-region-trait-bound-closure.rs:86:1 + | +86 | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +87 | | where +88 | | T: Anything<'b>, +89 | | 'b: 'a, +90 | | { +91 | | with_signature(cell, t, |cell, t| require(cell, t)); +92 | | } + | |_^ + | + = note: defining type: DefId(0/0:11 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]) with substs [ + '_#1r, + '_#2r, + T + ] + +note: No external requirements + --> $DIR/projection-one-region-trait-bound-closure.rs:95:1 + | +95 | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T) +96 | | where +97 | | T: Anything<'a>, +98 | | { +... | +103 | | with_signature(cell, t, |cell, t| require(cell, t)); +104 | | } + | |_^ + | + = note: defining type: DefId(0/0:12 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]) with substs [ + '_#1r, + T + ] + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs new file mode 100644 index 00000000000..67e28af1146 --- /dev/null +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs @@ -0,0 +1,99 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test cases where we constrain `>::AssocType` to +// outlive `'static`. In this case, we don't get any errors, and in fact +// we don't even propagate constraints from the closures to the callers. + +// compile-flags:-Znll -Zborrowck=mir -Zverbose +// must-compile-successfully + +#![allow(warnings)] +#![feature(dyn_trait)] +#![feature(rustc_attrs)] + +use std::cell::Cell; + +trait Anything<'a> { + type AssocType: 'static; +} + +fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F) +where + F: FnOnce(Cell<&'a ()>, T), +{ + op(cell, t) +} + +fn require<'a, 'b, T>(_cell: Cell<&'a ()>, _t: T) +where + T: Anything<'b>, + T::AssocType: 'a, +{ +} + +#[rustc_regions] +fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'b>, +{ + with_signature(cell, t, |cell, t| require(cell, t)); +} + +#[rustc_regions] +fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'b>, + 'a: 'a, +{ + with_signature(cell, t, |cell, t| require(cell, t)); +} + +#[rustc_regions] +fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'b>, + T::AssocType: 'a, +{ + // This error is unfortunate. This code ought to type-check: we + // are projecting `>::AssocType`, and we know + // that this outlives `'a` because of the where-clause. However, + // the way the region checker works, we don't register this + // outlives obligation, and hence we get an error: this is because + // what we see is a projection like `>::AssocType`, and we don't yet know if `?0` will + // equal `'b` or not, so we ignore the where-clause. Obviously we + // can do better here with a more involved verification step. + + with_signature(cell, t, |cell, t| require(cell, t)); +} + +#[rustc_regions] +fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'b>, + 'b: 'a, +{ + with_signature(cell, t, |cell, t| require(cell, t)); +} + +#[rustc_regions] +fn one_region<'a, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'a>, +{ + // Note that in this case the closure still propagates an external + // requirement between two variables in its signature, but the + // creator maps both those two region variables to `'a` on its + // side. + with_signature(cell, t, |cell, t| require(cell, t)); +} + +fn main() {} diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr new file mode 100644 index 00000000000..986676d28d9 --- /dev/null +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr @@ -0,0 +1,155 @@ +note: No external requirements + --> $DIR/projection-one-region-trait-bound-static-closure.rs:47:29 + | +47 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:19 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + +note: No external requirements + --> $DIR/projection-one-region-trait-bound-static-closure.rs:56:29 + | +56 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + +note: No external requirements + --> $DIR/projection-one-region-trait-bound-static-closure.rs:75:29 + | +75 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + +note: No external requirements + --> $DIR/projection-one-region-trait-bound-static-closure.rs:84:29 + | +84 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + +note: No external requirements + --> $DIR/projection-one-region-trait-bound-static-closure.rs:96:29 + | +96 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + +note: No external requirements + --> $DIR/projection-one-region-trait-bound-static-closure.rs:43:1 + | +43 | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +44 | | where +45 | | T: Anything<'b>, +46 | | { +47 | | with_signature(cell, t, |cell, t| require(cell, t)); +48 | | } + | |_^ + | + = note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]) with substs [ + '_#1r, + T + ] + +note: No external requirements + --> $DIR/projection-one-region-trait-bound-static-closure.rs:51:1 + | +51 | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +52 | | where +53 | | T: Anything<'b>, +54 | | 'a: 'a, +55 | | { +56 | | with_signature(cell, t, |cell, t| require(cell, t)); +57 | | } + | |_^ + | + = note: defining type: DefId(0/0:9 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]) with substs [ + '_#1r, + '_#2r, + T + ] + +note: No external requirements + --> $DIR/projection-one-region-trait-bound-static-closure.rs:60:1 + | +60 | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +61 | | where +62 | | T: Anything<'b>, +63 | | T::AssocType: 'a, +... | +75 | | with_signature(cell, t, |cell, t| require(cell, t)); +76 | | } + | |_^ + | + = note: defining type: DefId(0/0:10 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]) with substs [ + '_#1r, + '_#2r, + T + ] + +note: No external requirements + --> $DIR/projection-one-region-trait-bound-static-closure.rs:79:1 + | +79 | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +80 | | where +81 | | T: Anything<'b>, +82 | | 'b: 'a, +83 | | { +84 | | with_signature(cell, t, |cell, t| require(cell, t)); +85 | | } + | |_^ + | + = note: defining type: DefId(0/0:11 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]) with substs [ + '_#1r, + '_#2r, + T + ] + +note: No external requirements + --> $DIR/projection-one-region-trait-bound-static-closure.rs:88:1 + | +88 | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T) +89 | | where +90 | | T: Anything<'a>, +91 | | { +... | +96 | | with_signature(cell, t, |cell, t| require(cell, t)); +97 | | } + | |_^ + | + = note: defining type: DefId(0/0:12 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]) with substs [ + '_#1r, + T + ] + diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs new file mode 100644 index 00000000000..f8f3065fff4 --- /dev/null +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs @@ -0,0 +1,135 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test cases where we constrain `>::AssocType` +// to outlive `'a` and there are two bounds in the trait definition of +// `Anything` -- i.e., we know that `AssocType` outlives `'a` and +// `'b`. In this case, it's not clear what is the best way to satisfy +// the trait bound, and hence we propagate it to the caller as a type +// test. + +// compile-flags:-Znll -Zborrowck=mir -Zverbose + +#![allow(warnings)] +#![feature(dyn_trait)] +#![feature(rustc_attrs)] + +use std::cell::Cell; + +trait Anything<'a, 'b> { + type AssocType: 'a + 'b; +} + +fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F) +where + F: FnOnce(Cell<&'a ()>, T), +{ + op(cell, t) +} + +fn require<'a, 'b, 'c, T>(_cell: Cell<&'a ()>, _t: T) +where + T: Anything<'b, 'c>, + T::AssocType: 'a, +{ +} + +#[rustc_regions] +fn no_relationships_late<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'b, 'c>, +{ + with_signature(cell, t, |cell, t| require(cell, t)); + //~^ WARNING not reporting region error due to -Znll + //~| ERROR failed type test +} + +#[rustc_regions] +fn no_relationships_early<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'b, 'c>, + 'a: 'a, +{ + with_signature(cell, t, |cell, t| require(cell, t)); + //~^ WARNING not reporting region error due to -Znll + //~| ERROR failed type test +} + +#[rustc_regions] +fn projection_outlives<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'b, 'c>, + T::AssocType: 'a, +{ + // This error is unfortunate. This code ought to type-check: we + // are projecting `>::AssocType`, and we know + // that this outlives `'a` because of the where-clause. However, + // the way the region checker works, we don't register this + // outlives obligation, and hence we get an error: this is because + // what we see is a projection like `>::AssocType`, and we don't yet know if `?0` will + // equal `'b` or not, so we ignore the where-clause. Obviously we + // can do better here with a more involved verification step. + + with_signature(cell, t, |cell, t| require(cell, t)); + //~^ WARNING not reporting region error due to -Znll + //~| ERROR failed type test +} + +#[rustc_regions] +fn elements_outlive1<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'b, 'c>, + 'b: 'a, +{ + with_signature(cell, t, |cell, t| require(cell, t)); +} + +#[rustc_regions] +fn elements_outlive2<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'b, 'c>, + 'c: 'a, +{ + with_signature(cell, t, |cell, t| require(cell, t)); +} + +#[rustc_regions] +fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'b, 'b>, +{ + with_signature(cell, t, |cell, t| require(cell, t)); + //~^ WARNING not reporting region error due to -Znll + //~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r` +} + +#[rustc_regions] +fn two_regions_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'b, 'b>, + 'b: 'a, +{ + with_signature(cell, t, |cell, t| require(cell, t)); +} + +#[rustc_regions] +fn one_region<'a, T>(cell: Cell<&'a ()>, t: T) +where + T: Anything<'a, 'a>, +{ + // Note that in this case the closure still propagates an external + // requirement between two variables in its signature, but the + // creator maps both those two region variables to `'a` on its + // side. + with_signature(cell, t, |cell, t| require(cell, t)); +} + +fn main() {} diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr new file mode 100644 index 00000000000..02650214129 --- /dev/null +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -0,0 +1,326 @@ +warning: not reporting region error due to -Znll + --> $DIR/projection-two-region-trait-bound-closure.rs:49:39 + | +49 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^ + +warning: not reporting region error due to -Znll + --> $DIR/projection-two-region-trait-bound-closure.rs:60:39 + | +60 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^ + +warning: not reporting region error due to -Znll + --> $DIR/projection-two-region-trait-bound-closure.rs:81:39 + | +81 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^ + +warning: not reporting region error due to -Znll + --> $DIR/projection-two-region-trait-bound-closure.rs:109:39 + | +109 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^ + +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:49:29 + | +49 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:22 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where >::AssocType: '_#3r + +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:60:29 + | +60 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:27 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + '_#3r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + ] + = note: number of external vids: 5 + = note: where >::AssocType: '_#4r + +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:81:29 + | +81 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:32 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + '_#3r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + ] + = note: number of external vids: 5 + = note: where >::AssocType: '_#4r + +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:92:29 + | +92 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:37 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + '_#3r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + ] + = note: number of external vids: 5 + = note: where >::AssocType: '_#4r + +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:101:29 + | +101 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:42 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + '_#3r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + ] + = note: number of external vids: 5 + = note: where >::AssocType: '_#4r + +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:109:29 + | +109 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:46 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + = note: number of external vids: 3 + = note: where >::AssocType: '_#2r + +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:120:29 + | +120 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:50 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where >::AssocType: '_#3r + +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:132:29 + | +132 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:53 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + = note: number of external vids: 3 + = note: where >::AssocType: '_#2r + +error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T, '_#5r, '_#6r]), item_def_id: DefId(0/0:5 ~ projection_two_region_trait_bound_closure[317d]::Anything[0]::AssocType[0]) }, lower_bound: '_#7r, point: bb0[5], span: $DIR/projection-two-region-trait-bound-closure.rs:49:29: 49:55, test: Any([IsOutlivedByAnyRegionIn(['_#6r, '_#5r]), All([IsOutlivedByAnyRegionIn(['_#4r]), IsOutlivedByAllRegionsIn(['_#5r, '_#6r])])]) } + --> $DIR/projection-two-region-trait-bound-closure.rs:49:29 + | +49 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: No external requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:45:1 + | +45 | / fn no_relationships_late<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) +46 | | where +47 | | T: Anything<'b, 'c>, +48 | | { +... | +51 | | //~| ERROR failed type test +52 | | } + | |_^ + | + = note: defining type: DefId(0/0:8 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [ + '_#1r, + '_#2r, + T + ] + +error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T, '_#6r, '_#7r]), item_def_id: DefId(0/0:5 ~ projection_two_region_trait_bound_closure[317d]::Anything[0]::AssocType[0]) }, lower_bound: '_#8r, point: bb0[5], span: $DIR/projection-two-region-trait-bound-closure.rs:60:29: 60:55, test: Any([IsOutlivedByAnyRegionIn(['_#7r, '_#6r]), All([IsOutlivedByAnyRegionIn(['_#4r]), IsOutlivedByAllRegionsIn(['_#6r, '_#7r])])]) } + --> $DIR/projection-two-region-trait-bound-closure.rs:60:29 + | +60 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: No external requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:55:1 + | +55 | / fn no_relationships_early<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) +56 | | where +57 | | T: Anything<'b, 'c>, +58 | | 'a: 'a, +... | +62 | | //~| ERROR failed type test +63 | | } + | |_^ + | + = note: defining type: DefId(0/0:9 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]) with substs [ + '_#1r, + '_#2r, + '_#3r, + T + ] + +error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T, '_#6r, '_#7r]), item_def_id: DefId(0/0:5 ~ projection_two_region_trait_bound_closure[317d]::Anything[0]::AssocType[0]) }, lower_bound: '_#8r, point: bb0[5], span: $DIR/projection-two-region-trait-bound-closure.rs:81:29: 81:55, test: Any([IsOutlivedByAnyRegionIn(['_#7r, '_#6r]), All([IsOutlivedByAnyRegionIn(['_#4r]), IsOutlivedByAllRegionsIn(['_#6r, '_#7r])])]) } + --> $DIR/projection-two-region-trait-bound-closure.rs:81:29 + | +81 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: No external requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:66:1 + | +66 | / fn projection_outlives<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) +67 | | where +68 | | T: Anything<'b, 'c>, +69 | | T::AssocType: 'a, +... | +83 | | //~| ERROR failed type test +84 | | } + | |_^ + | + = note: defining type: DefId(0/0:10 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]) with substs [ + '_#1r, + '_#2r, + '_#3r, + T + ] + +note: No external requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:87:1 + | +87 | / fn elements_outlive1<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) +88 | | where +89 | | T: Anything<'b, 'c>, +90 | | 'b: 'a, +91 | | { +92 | | with_signature(cell, t, |cell, t| require(cell, t)); +93 | | } + | |_^ + | + = note: defining type: DefId(0/0:11 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]) with substs [ + '_#1r, + '_#2r, + '_#3r, + T + ] + +note: No external requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:96:1 + | +96 | / fn elements_outlive2<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) +97 | | where +98 | | T: Anything<'b, 'c>, +99 | | 'c: 'a, +100 | | { +101 | | with_signature(cell, t, |cell, t| require(cell, t)); +102 | | } + | |_^ + | + = note: defining type: DefId(0/0:12 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]) with substs [ + '_#1r, + '_#2r, + '_#3r, + T + ] + +error: free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r` + --> $DIR/projection-two-region-trait-bound-closure.rs:109:20 + | +109 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^ + +note: No external requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:105:1 + | +105 | / fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +106 | | where +107 | | T: Anything<'b, 'b>, +108 | | { +... | +111 | | //~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r` +112 | | } + | |_^ + | + = note: defining type: DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]) with substs [ + '_#1r, + T + ] + +note: No external requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:115:1 + | +115 | / fn two_regions_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +116 | | where +117 | | T: Anything<'b, 'b>, +118 | | 'b: 'a, +119 | | { +120 | | with_signature(cell, t, |cell, t| require(cell, t)); +121 | | } + | |_^ + | + = note: defining type: DefId(0/0:14 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]) with substs [ + '_#1r, + '_#2r, + T + ] + +note: No external requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:124:1 + | +124 | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T) +125 | | where +126 | | T: Anything<'a, 'a>, +127 | | { +... | +132 | | with_signature(cell, t, |cell, t| require(cell, t)); +133 | | } + | |_^ + | + = note: defining type: DefId(0/0:15 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]) with substs [ + '_#1r, + T + ] + +error: aborting due to 4 previous errors + -- cgit 1.4.1-3-g733a5 From e9824c50edd067fefb2e4fd6f6d1a4fe739a145b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 6 Dec 2017 04:30:58 -0500 Subject: impose inputs/ouputs on MIR after the fact The input/output types found in `UniversalRegions` are not normalized. The old code used to assign them directly into the MIR, which would lead to errors when there was a projection in a argument or return type. This also led to some special cases in the `renumber` code. We now renumber uniformly but then pass the input/output types into the MIR type-checker, which equates them with the types found in MIR. This allows us to normalize at the same time. --- src/librustc_mir/borrow_check/nll/mod.rs | 4 +- src/librustc_mir/borrow_check/nll/renumber.rs | 68 ++-------------------- .../borrow_check/nll/type_check/mod.rs | 49 +++++++++++++++- .../borrow_check/nll/universal_regions.rs | 6 +- src/test/mir-opt/nll/named-lifetimes-basic.rs | 6 +- src/test/ui/nll/projection-return.rs | 29 +++++++++ 6 files changed, 94 insertions(+), 68 deletions(-) create mode 100644 src/test/ui/nll/projection-return.rs (limited to 'src/test') 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(&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>, 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 or the MIT license +// , 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() { } + -- cgit 1.4.1-3-g733a5 From a118afe7ca742872f2064e26ddf97394d091ce3b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 6 Dec 2017 04:56:03 -0500 Subject: add a test regarding relating closure and fn generics Turns out this works but we had no test targeting it. --- .../propagate-from-trait-match.rs | 59 +++++++++++++++++++++ .../propagate-from-trait-match.stderr | 60 ++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 src/test/ui/nll/closure-requirements/propagate-from-trait-match.rs create mode 100644 src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr (limited to 'src/test') diff --git a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.rs b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.rs new file mode 100644 index 00000000000..d5bd4b60118 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.rs @@ -0,0 +1,59 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that regions which appear only in the closure's generics (in +// this case, `'a`) are properly mapped to the creator's generics. In +// this case, the closure constrains its type parameter `T` to outlive +// the same `'a` for which it implements `Trait`, which can only be the `'a` +// from the function definition. + +// compile-flags:-Znll -Zborrowck=mir -Zverbose + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +trait Trait<'a> {} + +fn establish_relationships(value: T, closure: F) +where + F: FnOnce(T), +{ + closure(value) +} + +fn require<'a, T>(t: T) +where + T: Trait<'a> + 'a, +{ +} + +#[rustc_regions] +fn supply<'a, T>(value: T) +where + T: Trait<'a>, +{ + establish_relationships(value, |value| { + // This function call requires that + // + // (a) T: Trait<'a> + // + // and + // + // (b) T: 'a + // + // The latter does not hold. + + require(value); + //~^ WARNING not reporting region error due to -Znll + //~| ERROR failed type test + }); +} + +fn main() {} diff --git a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr new file mode 100644 index 00000000000..eb415ec8d1a --- /dev/null +++ b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr @@ -0,0 +1,60 @@ +warning: not reporting region error due to -Znll + --> $DIR/propagate-from-trait-match.rs:53:9 + | +53 | require(value); + | ^^^^^^^ + +note: External requirements + --> $DIR/propagate-from-trait-match.rs:42:36 + | +42 | establish_relationships(value, |value| { + | ____________________________________^ +43 | | // This function call requires that +44 | | // +45 | | // (a) T: Trait<'a> +... | +55 | | //~| ERROR failed type test +56 | | }); + | |_____^ + | + = note: defining type: DefId(0/1:16 ~ propagate_from_trait_match[317d]::supply[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((T,)) + ] + = note: number of external vids: 2 + = note: where T: '_#1r + +error: failed type test: TypeTest { generic_kind: T/#1, lower_bound: '_#3r, point: bb0[3], span: $DIR/propagate-from-trait-match.rs:42:36: 56:6, test: IsOutlivedByAnyRegionIn(['_#2r]) } + --> $DIR/propagate-from-trait-match.rs:42:36 + | +42 | establish_relationships(value, |value| { + | ____________________________________^ +43 | | // This function call requires that +44 | | // +45 | | // (a) T: Trait<'a> +... | +55 | | //~| ERROR failed type test +56 | | }); + | |_____^ + +note: No external requirements + --> $DIR/propagate-from-trait-match.rs:38:1 + | +38 | / fn supply<'a, T>(value: T) +39 | | where +40 | | T: Trait<'a>, +41 | | { +... | +56 | | }); +57 | | } + | |_^ + | + = note: defining type: DefId(0/0:6 ~ propagate_from_trait_match[317d]::supply[0]) with substs [ + '_#1r, + T + ] + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 0d6bd42abb0b6082d23e7fe84b0121dfa0476b78 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 6 Dec 2017 05:50:49 -0500 Subject: make `blame_span` deterministic --- .../borrow_check/nll/region_infer/mod.rs | 60 ++++++++++++++-------- src/test/compile-fail/mir_check_cast_closure.rs | 2 +- src/test/compile-fail/mir_check_cast_reify.rs | 2 +- src/test/compile-fail/mir_check_cast_unsafe_fn.rs | 2 +- .../propagate-approximated-fail-no-postdom.rs | 2 +- .../propagate-approximated-fail-no-postdom.stderr | 10 ++-- .../propagate-approximated-ref.stderr | 4 +- .../propagate-approximated-to-empty.stderr | 4 +- .../propagate-approximated-val.stderr | 4 +- .../propagate-from-trait-match.rs | 3 +- .../propagate-from-trait-match.stderr | 30 +++++------ 11 files changed, 71 insertions(+), 52 deletions(-) (limited to 'src/test') 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 f03e8bd7ac1..9a3076c0c32 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -872,35 +872,50 @@ impl<'tcx> RegionInferenceContext<'tcx> { // be obvious to the user -- not to mention the naive notion // of dependencies, which doesn't account for the locations of // contraints at all. But it will do for now. - for constraint in &self.constraints { - if constraint.sub == fr2 && influenced_fr1[constraint.sup] { - return constraint.span; - } - } - - bug!( - "could not find any constraint to blame for {:?}: {:?}", - fr1, - fr2 - ); + let relevant_constraint = self.constraints + .iter() + .filter_map(|constraint| { + if constraint.sub != fr2 { + None + } else { + influenced_fr1[constraint.sup] + .map(|distance| (distance, constraint.span)) + } + }) + .min() // constraining fr1 with fewer hops *ought* to be more obvious + .map(|(_dist, span)| span); + + relevant_constraint.unwrap_or_else(|| { + bug!( + "could not find any constraint to blame for {:?}: {:?}", + fr1, + fr2 + ); + }) } /// Finds all regions whose values `'a` may depend on in some way. - /// Basically if there exists a constraint `'a: 'b @ P`, then `'b` - /// and `dependencies('b)` will be in the final set. + /// For each region, returns either `None` (does not influence + /// `'a`) or `Some(d)` which indicates that it influences `'a` + /// with distinct `d` (minimum number of edges that must be + /// traversed). /// /// Used during error reporting, extremely naive and inefficient. - fn dependencies(&self, r0: RegionVid) -> IndexVec { - let mut result_set = IndexVec::from_elem(false, &self.definitions); + fn dependencies(&self, r0: RegionVid) -> IndexVec> { + let mut result_set = IndexVec::from_elem(None, &self.definitions); let mut changed = true; - result_set[r0] = true; + result_set[r0] = Some(0); // distance 0 from `r0` while changed { changed = false; for constraint in &self.constraints { - if result_set[constraint.sup] { - if !result_set[constraint.sub] { - result_set[constraint.sub] = true; + if let Some(n) = result_set[constraint.sup] { + let m = n + 1; + if result_set[constraint.sub] + .map(|distance| m < distance) + .unwrap_or(true) + { + result_set[constraint.sub] = Some(m); changed = true; } } @@ -1049,13 +1064,16 @@ impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequi value: &T, ) -> T where - T: TypeFoldable<'tcx> + T: TypeFoldable<'tcx>, { infcx.tcx.fold_regions(value, &mut false, |r, _depth| { if let ty::ReClosureBound(vid) = r { closure_mapping[*vid] } else { - bug!("subst_closure_mapping: encountered non-closure bound free region {:?}", r) + bug!( + "subst_closure_mapping: encountered non-closure bound free region {:?}", + r + ) } }) } diff --git a/src/test/compile-fail/mir_check_cast_closure.rs b/src/test/compile-fail/mir_check_cast_closure.rs index be0d4b13741..6562efeb6d8 100644 --- a/src/test/compile-fail/mir_check_cast_closure.rs +++ b/src/test/compile-fail/mir_check_cast_closure.rs @@ -14,9 +14,9 @@ fn bar<'a, 'b>() -> fn(&'a u32, &'b u32) -> &'a u32 { let g: fn(_, _) -> _ = |_x, y| y; + //~^ ERROR free region `'b` does not outlive free region `'a` g //~^ WARNING not reporting region error due to -Znll - //~| ERROR free region `'b` does not outlive free region `'a` } fn main() {} diff --git a/src/test/compile-fail/mir_check_cast_reify.rs b/src/test/compile-fail/mir_check_cast_reify.rs index 091e0b71b2d..1736aea2d6d 100644 --- a/src/test/compile-fail/mir_check_cast_reify.rs +++ b/src/test/compile-fail/mir_check_cast_reify.rs @@ -45,8 +45,8 @@ fn bar<'a>(x: &'a u32) -> &'static u32 { // as part of checking the `ReifyFnPointer`. let f: fn(_) -> _ = foo; //~^ WARNING not reporting region error due to -Znll + //~| ERROR free region `'_#1r` does not outlive free region `'static` f(x) - //~^ ERROR free region `'_#1r` does not outlive free region `'static` } fn main() {} diff --git a/src/test/compile-fail/mir_check_cast_unsafe_fn.rs b/src/test/compile-fail/mir_check_cast_unsafe_fn.rs index 701a7c6b056..39eafa10040 100644 --- a/src/test/compile-fail/mir_check_cast_unsafe_fn.rs +++ b/src/test/compile-fail/mir_check_cast_unsafe_fn.rs @@ -17,8 +17,8 @@ fn bar<'a>(input: &'a u32, f: fn(&'a u32) -> &'a u32) -> &'static u32 { // in `g`. These are related via the `UnsafeFnPointer` cast. let g: unsafe fn(_) -> _ = f; //~^ WARNING not reporting region error due to -Znll + //~| ERROR free region `'_#1r` does not outlive free region `'static` unsafe { g(input) } - //~^ ERROR free region `'_#1r` does not outlive free region `'static` } fn main() {} diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs index c2f071cc029..50d7877de50 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs @@ -54,8 +54,8 @@ fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell // Only works if 'x: 'y: let p = x.get(); //~^ WARN not reporting region error due to -Znll + //~| ERROR free region `'_#5r` does not outlive free region `'_#6r` demand_y(x, y, p) - //~^ ERROR free region `'_#5r` does not outlive free region `'_#6r` }, ); } diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr index cdda8ab5392..f90bc7c175a 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -5,10 +5,10 @@ warning: not reporting region error due to -Znll | ^^^^^^^ error: free region `'_#5r` does not outlive free region `'_#6r` - --> $DIR/propagate-approximated-fail-no-postdom.rs:57:25 + --> $DIR/propagate-approximated-fail-no-postdom.rs:55:17 | -57 | demand_y(x, y, p) - | ^ +55 | let p = x.get(); + | ^ note: No external requirements --> $DIR/propagate-approximated-fail-no-postdom.rs:53:9 @@ -17,8 +17,8 @@ note: No external requirements 54 | | // Only works if 'x: 'y: 55 | | let p = x.get(); 56 | | //~^ WARN not reporting region error due to -Znll -57 | | demand_y(x, y, p) -58 | | //~^ ERROR free region `'_#5r` does not outlive free region `'_#6r` +57 | | //~| ERROR free region `'_#5r` does not outlive free region `'_#6r` +58 | | demand_y(x, y, p) 59 | | }, | |_________^ | diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr index 717cf481a01..4bae29ad326 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr @@ -24,10 +24,10 @@ note: External requirements = note: where '_#1r: '_#2r error: free region `'_#1r` does not outlive free region `'_#2r` - --> $DIR/propagate-approximated-ref.rs:53:38 + --> $DIR/propagate-approximated-ref.rs:53:29 | 53 | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { - | ^^^^^^^ + | ^^^^^^^ note: No external requirements --> $DIR/propagate-approximated-ref.rs:52:1 diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-to-empty.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-to-empty.stderr index e8dc8a13f87..502b344c89e 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-to-empty.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-to-empty.stderr @@ -5,10 +5,10 @@ warning: not reporting region error due to -Znll | ^^^^^^^^^^^^^^^^^^^^^^^ error: free region `'_#6r` does not outlive free region `'_#4r` - --> $DIR/propagate-approximated-to-empty.rs:41:21 + --> $DIR/propagate-approximated-to-empty.rs:41:18 | 41 | demand_y(x, y, x.get()) - | ^ + | ^ note: No external requirements --> $DIR/propagate-approximated-to-empty.rs:39:47 diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr index 43464bfb2b9..43d61fdf1b5 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr @@ -24,10 +24,10 @@ note: External requirements = note: where '_#1r: '_#2r error: free region `'_#1r` does not outlive free region `'_#2r` - --> $DIR/propagate-approximated-val.rs:46:37 + --> $DIR/propagate-approximated-val.rs:46:29 | 46 | establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| { - | ^^^^^^ + | ^^^^^^ note: No external requirements --> $DIR/propagate-approximated-val.rs:45:1 diff --git a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.rs b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.rs index d5bd4b60118..a5be2b43f04 100644 --- a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.rs +++ b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.rs @@ -40,6 +40,8 @@ where T: Trait<'a>, { establish_relationships(value, |value| { + //~^ ERROR failed type test + // This function call requires that // // (a) T: Trait<'a> @@ -52,7 +54,6 @@ where require(value); //~^ WARNING not reporting region error due to -Znll - //~| ERROR failed type test }); } diff --git a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr index eb415ec8d1a..e81c45ef7ed 100644 --- a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr @@ -1,7 +1,7 @@ warning: not reporting region error due to -Znll - --> $DIR/propagate-from-trait-match.rs:53:9 + --> $DIR/propagate-from-trait-match.rs:55:9 | -53 | require(value); +55 | require(value); | ^^^^^^^ note: External requirements @@ -9,12 +9,12 @@ note: External requirements | 42 | establish_relationships(value, |value| { | ____________________________________^ -43 | | // This function call requires that -44 | | // -45 | | // (a) T: Trait<'a> +43 | | //~^ ERROR failed type test +44 | | +45 | | // This function call requires that ... | -55 | | //~| ERROR failed type test -56 | | }); +56 | | //~^ WARNING not reporting region error due to -Znll +57 | | }); | |_____^ | = note: defining type: DefId(0/1:16 ~ propagate_from_trait_match[317d]::supply[0]::{{closure}}[0]) with closure substs [ @@ -26,17 +26,17 @@ note: External requirements = note: number of external vids: 2 = note: where T: '_#1r -error: failed type test: TypeTest { generic_kind: T/#1, lower_bound: '_#3r, point: bb0[3], span: $DIR/propagate-from-trait-match.rs:42:36: 56:6, test: IsOutlivedByAnyRegionIn(['_#2r]) } +error: failed type test: TypeTest { generic_kind: T/#1, lower_bound: '_#3r, point: bb0[3], span: $DIR/propagate-from-trait-match.rs:42:36: 57:6, test: IsOutlivedByAnyRegionIn(['_#2r]) } --> $DIR/propagate-from-trait-match.rs:42:36 | 42 | establish_relationships(value, |value| { | ____________________________________^ -43 | | // This function call requires that -44 | | // -45 | | // (a) T: Trait<'a> +43 | | //~^ ERROR failed type test +44 | | +45 | | // This function call requires that ... | -55 | | //~| ERROR failed type test -56 | | }); +56 | | //~^ WARNING not reporting region error due to -Znll +57 | | }); | |_____^ note: No external requirements @@ -47,8 +47,8 @@ note: No external requirements 40 | | T: Trait<'a>, 41 | | { ... | -56 | | }); -57 | | } +57 | | }); +58 | | } | |_^ | = note: defining type: DefId(0/0:6 ~ propagate_from_trait_match[317d]::supply[0]) with substs [ -- cgit 1.4.1-3-g733a5 From 0f8ef0ca1a298619001998fcb5c329159db206c7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 6 Dec 2017 17:11:16 -0500 Subject: more concise debug output when dumping the value of a region --- .../borrow_check/nll/region_infer/values.rs | 63 +++++++++++++++++++--- src/test/mir-opt/nll/named-lifetimes-basic.rs | 18 +++---- src/test/mir-opt/nll/reborrow-basic.rs | 4 +- src/test/mir-opt/nll/region-liveness-basic.rs | 4 +- .../mir-opt/nll/region-liveness-drop-may-dangle.rs | 2 +- .../nll/region-liveness-drop-no-may-dangle.rs | 2 +- .../nll/region-liveness-two-disjoint-uses.rs | 6 +-- src/test/mir-opt/nll/region-subtyping-basic.rs | 6 +-- 8 files changed, 77 insertions(+), 28 deletions(-) (limited to 'src/test') diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index 849ccd3259a..5f23a0e5790 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -215,8 +215,11 @@ impl RegionValues { // FIXME. We could optimize this by improving // `BitMatrix::merge` so it does not always merge an entire // row. - debug!("add_universal_regions_outlived_by(from_region={:?}, to_region={:?})", - from_region, to_region); + debug!( + "add_universal_regions_outlived_by(from_region={:?}, to_region={:?})", + from_region, + to_region + ); let mut changed = false; for elem in self.elements.all_universal_region_indices() { if self.contains(from_region, elem) { @@ -269,24 +272,70 @@ impl RegionValues { let mut result = String::new(); result.push_str("{"); - for (index, element) in self.elements_contained_in(r).enumerate() { - if index > 0 { - result.push_str(", "); - } + // Set to Some(l1, l2) when we have observed all the locations + // from l1..=l2 (inclusive) but not yet printed them. This + // gets extended if we then see l3 where l3 is the successor + // to l2. + let mut open_location: Option<(Location, Location)> = None; + + let mut sep = ""; + let mut push_sep = |s: &mut String| { + s.push_str(sep); + sep = ", "; + }; + for element in self.elements_contained_in(r) { match element { RegionElement::Location(l) => { - result.push_str(&format!("{:?}", l)); + if let Some((location1, location2)) = open_location { + if location2.block == l.block + && location2.statement_index == l.statement_index - 1 + { + open_location = Some((location1, l)); + continue; + } + + push_sep(&mut result); + Self::push_location_range(&mut result, location1, location2); + } + + open_location = Some((l, l)); } RegionElement::UniversalRegion(fr) => { + if let Some((location1, location2)) = open_location { + push_sep(&mut result); + Self::push_location_range(&mut result, location1, location2); + open_location = None; + } + + push_sep(&mut result); result.push_str(&format!("{:?}", fr)); } } } + if let Some((location1, location2)) = open_location { + push_sep(&mut result); + Self::push_location_range(&mut result, location1, location2); + } + result.push_str("}"); result } + + fn push_location_range(str: &mut String, location1: Location, location2: Location) { + if location1 == location2 { + str.push_str(&format!("{:?}", location1)); + } else { + assert_eq!(location1.block, location2.block); + str.push_str(&format!( + "{:?}[{}..={}]", + location1.block, + location1.statement_index, + location2.statement_index + )); + } + } } diff --git a/src/test/mir-opt/nll/named-lifetimes-basic.rs b/src/test/mir-opt/nll/named-lifetimes-basic.rs index f14979f9733..8feac15d69a 100644 --- a/src/test/mir-opt/nll/named-lifetimes-basic.rs +++ b/src/test/mir-opt/nll/named-lifetimes-basic.rs @@ -34,15 +34,15 @@ fn main() { // | '_#4r | Local | ['_#4r] // | // | Inferred Region Values -// | '_#0r | {'_#0r, bb0[0], bb0[1]} -// | '_#1r | {'_#1r, bb0[0], bb0[1]} -// | '_#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]} +// | '_#0r | {'_#0r, bb0[0..=1]} +// | '_#1r | {'_#1r, bb0[0..=1]} +// | '_#2r | {'_#2r, bb0[0..=1]} +// | '_#3r | {'_#3r, bb0[0..=1]} +// | '_#4r | {'_#4r, bb0[0..=1]} +// | '_#5r | {'_#1r, bb0[0..=1]} +// | '_#6r | {'_#2r, bb0[0..=1]} +// | '_#7r | {'_#1r, bb0[0..=1]} +// | '_#8r | {'_#3r, bb0[0..=1]} // | // ... // fn use_x(_1: &'_#5r mut i32, _2: &'_#6r u32, _3: &'_#7r u32, _4: &'_#8r u32) -> bool { diff --git a/src/test/mir-opt/nll/reborrow-basic.rs b/src/test/mir-opt/nll/reborrow-basic.rs index 9e6d6aaee15..f69c51c3562 100644 --- a/src/test/mir-opt/nll/reborrow-basic.rs +++ b/src/test/mir-opt/nll/reborrow-basic.rs @@ -28,9 +28,9 @@ fn main() { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#7r | {bb0[6], bb0[7], bb0[8], bb0[9], bb0[10], bb0[11], bb0[12], bb0[13], bb0[14]} +// | '_#7r | {bb0[6..=14]} // ... -// | '_#9r | {bb0[11], bb0[12], bb0[13], bb0[14]} +// | '_#9r | {bb0[11..=14]} // ... // let _2: &'_#7r mut i32; // ... diff --git a/src/test/mir-opt/nll/region-liveness-basic.rs b/src/test/mir-opt/nll/region-liveness-basic.rs index ab99d79d7f3..e9834305550 100644 --- a/src/test/mir-opt/nll/region-liveness-basic.rs +++ b/src/test/mir-opt/nll/region-liveness-basic.rs @@ -31,8 +31,8 @@ fn main() { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#2r | {bb2[0], bb2[1], bb3[0], bb3[1]} -// | '_#3r | {bb2[1], bb3[0], bb3[1]} +// | '_#2r | {bb2[0..=1], bb3[0..=1]} +// | '_#3r | {bb2[1], bb3[0..=1]} // ... // let _2: &'_#3r usize; // END rustc.main.nll.0.mir diff --git a/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs b/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs index 515772a9427..c14ce6bb581 100644 --- a/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs +++ b/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs @@ -44,7 +44,7 @@ unsafe impl<#[may_dangle] T> Drop for Wrap { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#6r | {bb2[3], bb2[4], bb2[5], bb3[0], bb3[1]} +// | '_#6r | {bb2[3..=5], bb3[0..=1]} // ... // let _2: Wrap<&'_#6r usize>; // END rustc.main.nll.0.mir diff --git a/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs b/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs index a257910b0b8..058a57fe612 100644 --- a/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs +++ b/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs @@ -46,7 +46,7 @@ impl Drop for Wrap { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#6r | {bb2[3], bb2[4], bb2[5], bb3[0], bb3[1], bb3[2], bb4[0], bb5[0], bb5[1], bb5[2], bb6[0], bb7[0], bb7[1], bb8[0]} +// | '_#6r | {bb2[3..=5], bb3[0..=2], bb4[0], bb5[0..=2], bb6[0], bb7[0..=1], bb8[0]} // ... // let _2: Wrap<&'_#6r usize>; // END rustc.main.nll.0.mir diff --git a/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs b/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs index 3041c2cb061..821cd736671 100644 --- a/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs +++ b/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs @@ -36,10 +36,10 @@ fn main() { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#2r | {bb2[0], bb2[1], bb3[0], bb3[1]} +// | '_#2r | {bb2[0..=1], bb3[0..=1]} // ... -// | '_#4r | {bb8[1], bb8[2], bb8[3], bb8[4]} -// | '_#5r | {bb2[1], bb3[0], bb3[1], bb8[2], bb8[3], bb8[4]} +// | '_#4r | {bb8[1..=4]} +// | '_#5r | {bb2[1], bb3[0..=1], bb8[2..=4]} // ... // let mut _2: &'_#5r usize; // ... diff --git a/src/test/mir-opt/nll/region-subtyping-basic.rs b/src/test/mir-opt/nll/region-subtyping-basic.rs index 5a3f831331c..a3f68ed5ebf 100644 --- a/src/test/mir-opt/nll/region-subtyping-basic.rs +++ b/src/test/mir-opt/nll/region-subtyping-basic.rs @@ -32,9 +32,9 @@ fn main() { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#2r | {bb2[0], bb2[1], bb2[2], bb2[3], bb2[4], bb2[5], bb2[6], bb3[0], bb3[1]} -// | '_#3r | {bb2[1], bb2[2], bb2[3], bb2[4], bb2[5], bb2[6], bb3[0], bb3[1]} -// | '_#4r | {bb2[5], bb2[6], bb3[0], bb3[1]} +// | '_#2r | {bb2[0..=6], bb3[0..=1]} +// | '_#3r | {bb2[1..=6], bb3[0..=1]} +// | '_#4r | {bb2[5..=6], bb3[0..=1]} // END rustc.main.nll.0.mir // START rustc.main.nll.0.mir // let _2: &'_#3r usize; -- cgit 1.4.1-3-g733a5 From 4f43c5b1e78115083254e6df12e0d34f7da9748b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 15 Dec 2017 17:04:48 -0500 Subject: stop dumping DefPath into "failed type test" errors The prior messages were not stable across platforms. --- src/librustc_mir/borrow_check/nll/region_infer/mod.rs | 6 +++++- .../nll/closure-requirements/propagate-from-trait-match.rs | 2 +- .../closure-requirements/propagate-from-trait-match.stderr | 6 +++--- .../ui/nll/ty-outlives/projection-no-regions-closure.rs | 4 ++-- .../nll/ty-outlives/projection-no-regions-closure.stderr | 8 ++++---- src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs | 4 ++-- .../ui/nll/ty-outlives/projection-no-regions-fn.stderr | 4 ++-- .../ui/nll/ty-outlives/projection-one-region-closure.rs | 6 +++--- .../nll/ty-outlives/projection-one-region-closure.stderr | 6 +++--- .../projection-two-region-trait-bound-closure.rs | 6 +++--- .../projection-two-region-trait-bound-closure.stderr | 12 ++++++------ .../ty-param-closure-outlives-from-return-type.rs | 4 ++-- .../ty-param-closure-outlives-from-return-type.stderr | 6 +++--- .../ty-param-closure-outlives-from-where-clause.rs | 4 ++-- .../ty-param-closure-outlives-from-where-clause.stderr | 14 +++++++------- src/test/ui/nll/ty-outlives/ty-param-fn-body.rs | 2 +- src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr | 2 +- src/test/ui/nll/ty-outlives/ty-param-fn.rs | 4 ++-- src/test/ui/nll/ty-outlives/ty-param-fn.stderr | 4 ++-- 19 files changed, 54 insertions(+), 50 deletions(-) (limited to 'src/test') 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 9a3076c0c32..36b59d9fb7d 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -466,7 +466,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Oh the humanity. Obviously we will do better than this error eventually. tcx.sess.span_err( type_test.span, - &format!("failed type test: {:?}", type_test), + &format!( + "`{}` does not outlive `{:?}`", + type_test.generic_kind, + type_test.lower_bound, + ), ); } } diff --git a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.rs b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.rs index a5be2b43f04..604c81da49d 100644 --- a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.rs +++ b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.rs @@ -40,7 +40,7 @@ where T: Trait<'a>, { establish_relationships(value, |value| { - //~^ ERROR failed type test + //~^ ERROR `T` does not outlive // This function call requires that // diff --git a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr index e81c45ef7ed..efac55f2bee 100644 --- a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr @@ -9,7 +9,7 @@ note: External requirements | 42 | establish_relationships(value, |value| { | ____________________________________^ -43 | | //~^ ERROR failed type test +43 | | //~^ ERROR `T` does not outlive 44 | | 45 | | // This function call requires that ... | @@ -26,12 +26,12 @@ note: External requirements = note: number of external vids: 2 = note: where T: '_#1r -error: failed type test: TypeTest { generic_kind: T/#1, lower_bound: '_#3r, point: bb0[3], span: $DIR/propagate-from-trait-match.rs:42:36: 57:6, test: IsOutlivedByAnyRegionIn(['_#2r]) } +error: `T` does not outlive `'_#3r` --> $DIR/propagate-from-trait-match.rs:42:36 | 42 | establish_relationships(value, |value| { | ____________________________________^ -43 | | //~^ ERROR failed type test +43 | | //~^ ERROR `T` does not outlive 44 | | 45 | | // This function call requires that ... | diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs index b91c01fb671..9451163ace9 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs @@ -35,7 +35,7 @@ where { with_signature(x, |mut y| Box::new(y.next())) //~^ WARNING not reporting region error due to -Znll - //~| ERROR failed type test + //~| ERROR `::Item` does not outlive } #[rustc_regions] @@ -53,7 +53,7 @@ where { with_signature(x, |mut y| Box::new(y.next())) //~^ WARNING not reporting region error due to -Znll - //~| ERROR failed type test + //~| ERROR `::Item` does not outlive } #[rustc_regions] diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr index 1d124f2d49a..9afd5d41182 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr @@ -72,7 +72,7 @@ note: External requirements = note: number of external vids: 4 = note: where ::Item: '_#3r -error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1697 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#4r, point: bb0[5], span: $DIR/projection-no-regions-closure.rs:36:23: 36:49, test: IsOutlivedByAnyRegionIn(['_#2r]) } +error: `::Item` does not outlive `'_#4r` --> $DIR/projection-no-regions-closure.rs:36:23 | 36 | with_signature(x, |mut y| Box::new(y.next())) @@ -86,7 +86,7 @@ note: No external requirements 34 | | T: Iterator, 35 | | { ... | -38 | | //~| ERROR failed type test +38 | | //~| ERROR `::Item` does not outlive 39 | | } | |_^ | @@ -111,7 +111,7 @@ note: No external requirements T ] -error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1697 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#6r, point: bb0[5], span: $DIR/projection-no-regions-closure.rs:54:23: 54:49, test: IsOutlivedByAnyRegionIn(['_#2r, '_#3r]) } +error: `::Item` does not outlive `'_#6r` --> $DIR/projection-no-regions-closure.rs:54:23 | 54 | with_signature(x, |mut y| Box::new(y.next())) @@ -125,7 +125,7 @@ note: No external requirements 52 | | T: 'b + Iterator, 53 | | { ... | -56 | | //~| ERROR failed type test +56 | | //~| ERROR `::Item` does not outlive 57 | | } | |_^ | diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs index b7822eb259b..c815fdc1a0c 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs @@ -23,7 +23,7 @@ where { Box::new(x.next()) //~^ WARNING not reporting region error due to -Znll - //~| ERROR failed type test + //~| ERROR `::Item` does not outlive } fn correct_region<'a, T>(mut x: T) -> Box @@ -39,7 +39,7 @@ where { Box::new(x.next()) //~^ WARNING not reporting region error due to -Znll - //~| ERROR failed type test + //~| ERROR `::Item` does not outlive } fn outlives_region<'a, 'b, T>(mut x: T) -> Box diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr index 5c3bd04f3b1..4d13972641c 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr @@ -10,13 +10,13 @@ warning: not reporting region error due to -Znll 40 | Box::new(x.next()) | ^^^^^^^^^^^^^^^^^^ -error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1697 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#4r, point: bb5[0], span: $DIR/projection-no-regions-fn.rs:24:5: 24:23, test: IsOutlivedByAnyRegionIn(['_#2r]) } +error: `::Item` does not outlive `'_#4r` --> $DIR/projection-no-regions-fn.rs:24:5 | 24 | Box::new(x.next()) | ^^^^^^^^^^^^^^^^^^ -error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1697 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#5r, point: bb5[0], span: $DIR/projection-no-regions-fn.rs:40:5: 40:23, test: IsOutlivedByAnyRegionIn(['_#2r, '_#3r]) } +error: `::Item` does not outlive `'_#5r` --> $DIR/projection-no-regions-fn.rs:40:5 | 40 | Box::new(x.next()) diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs index cd9b1c2a8ce..e2a2d20d77d 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs @@ -55,7 +55,7 @@ where { with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to -Znll - //~| ERROR failed type test + //~| ERROR `T` does not outlive //~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r` } @@ -67,7 +67,7 @@ where { with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to -Znll - //~| ERROR failed type test + //~| ERROR `T` does not outlive //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` } @@ -89,7 +89,7 @@ where with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to -Znll - //~| ERROR failed type test + //~| ERROR `T` does not outlive //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` } diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr index d187a094ec6..cbd80d70bf9 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -83,7 +83,7 @@ note: External requirements = note: where T: '_#3r = note: where '_#2r: '_#3r -error: failed type test: TypeTest { generic_kind: T/#1, lower_bound: '_#5r, point: bb0[5], span: $DIR/projection-one-region-closure.rs:56:29: 56:55, test: IsOutlivedByAnyRegionIn(['_#3r]) } +error: `T` does not outlive `'_#5r` --> $DIR/projection-one-region-closure.rs:56:29 | 56 | with_signature(cell, t, |cell, t| require(cell, t)); @@ -112,7 +112,7 @@ note: No external requirements T ] -error: failed type test: TypeTest { generic_kind: T/#2, lower_bound: '_#6r, point: bb0[5], span: $DIR/projection-one-region-closure.rs:68:29: 68:55, test: IsOutlivedByAnyRegionIn(['_#3r]) } +error: `T` does not outlive `'_#6r` --> $DIR/projection-one-region-closure.rs:68:29 | 68 | with_signature(cell, t, |cell, t| require(cell, t)); @@ -142,7 +142,7 @@ note: No external requirements T ] -error: failed type test: TypeTest { generic_kind: T/#2, lower_bound: '_#6r, point: bb0[5], span: $DIR/projection-one-region-closure.rs:90:29: 90:55, test: IsOutlivedByAnyRegionIn(['_#3r]) } +error: `T` does not outlive `'_#6r` --> $DIR/projection-one-region-closure.rs:90:29 | 90 | with_signature(cell, t, |cell, t| require(cell, t)); diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs index f8f3065fff4..42bfdfcf9f9 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs @@ -48,7 +48,7 @@ where { with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to -Znll - //~| ERROR failed type test + //~| ERROR `>::AssocType` does not outlive `'_#7r` } #[rustc_regions] @@ -59,7 +59,7 @@ where { with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to -Znll - //~| ERROR failed type test + //~| ERROR `>::AssocType` does not outlive `'_#8r` } #[rustc_regions] @@ -80,7 +80,7 @@ where with_signature(cell, t, |cell, t| require(cell, t)); //~^ WARNING not reporting region error due to -Znll - //~| ERROR failed type test + //~| ERROR `>::AssocType` does not outlive `'_#8r` } #[rustc_regions] diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr index 02650214129..5b708a0d7e6 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -152,7 +152,7 @@ note: External requirements = note: number of external vids: 3 = note: where >::AssocType: '_#2r -error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T, '_#5r, '_#6r]), item_def_id: DefId(0/0:5 ~ projection_two_region_trait_bound_closure[317d]::Anything[0]::AssocType[0]) }, lower_bound: '_#7r, point: bb0[5], span: $DIR/projection-two-region-trait-bound-closure.rs:49:29: 49:55, test: Any([IsOutlivedByAnyRegionIn(['_#6r, '_#5r]), All([IsOutlivedByAnyRegionIn(['_#4r]), IsOutlivedByAllRegionsIn(['_#5r, '_#6r])])]) } +error: `>::AssocType` does not outlive `'_#7r` --> $DIR/projection-two-region-trait-bound-closure.rs:49:29 | 49 | with_signature(cell, t, |cell, t| require(cell, t)); @@ -166,7 +166,7 @@ note: No external requirements 47 | | T: Anything<'b, 'c>, 48 | | { ... | -51 | | //~| ERROR failed type test +51 | | //~| ERROR `>::AssocType` does not outlive `'_#7r` 52 | | } | |_^ | @@ -176,7 +176,7 @@ note: No external requirements T ] -error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T, '_#6r, '_#7r]), item_def_id: DefId(0/0:5 ~ projection_two_region_trait_bound_closure[317d]::Anything[0]::AssocType[0]) }, lower_bound: '_#8r, point: bb0[5], span: $DIR/projection-two-region-trait-bound-closure.rs:60:29: 60:55, test: Any([IsOutlivedByAnyRegionIn(['_#7r, '_#6r]), All([IsOutlivedByAnyRegionIn(['_#4r]), IsOutlivedByAllRegionsIn(['_#6r, '_#7r])])]) } +error: `>::AssocType` does not outlive `'_#8r` --> $DIR/projection-two-region-trait-bound-closure.rs:60:29 | 60 | with_signature(cell, t, |cell, t| require(cell, t)); @@ -190,7 +190,7 @@ note: No external requirements 57 | | T: Anything<'b, 'c>, 58 | | 'a: 'a, ... | -62 | | //~| ERROR failed type test +62 | | //~| ERROR `>::AssocType` does not outlive `'_#8r` 63 | | } | |_^ | @@ -201,7 +201,7 @@ note: No external requirements T ] -error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T, '_#6r, '_#7r]), item_def_id: DefId(0/0:5 ~ projection_two_region_trait_bound_closure[317d]::Anything[0]::AssocType[0]) }, lower_bound: '_#8r, point: bb0[5], span: $DIR/projection-two-region-trait-bound-closure.rs:81:29: 81:55, test: Any([IsOutlivedByAnyRegionIn(['_#7r, '_#6r]), All([IsOutlivedByAnyRegionIn(['_#4r]), IsOutlivedByAllRegionsIn(['_#6r, '_#7r])])]) } +error: `>::AssocType` does not outlive `'_#8r` --> $DIR/projection-two-region-trait-bound-closure.rs:81:29 | 81 | with_signature(cell, t, |cell, t| require(cell, t)); @@ -215,7 +215,7 @@ note: No external requirements 68 | | T: Anything<'b, 'c>, 69 | | T::AssocType: 'a, ... | -83 | | //~| ERROR failed type test +83 | | //~| ERROR `>::AssocType` does not outlive `'_#8r` 84 | | } | |_^ | diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs index 6b23c82c771..14e2eb26976 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs @@ -36,7 +36,7 @@ where with_signature(x, |y| y) //~^ WARNING not reporting region error due to -Znll - //~| ERROR failed type test + //~| ERROR `T` does not outlive } fn correct_region<'a, T>(x: Box) -> Box @@ -52,7 +52,7 @@ where { x //~^ WARNING not reporting region error due to -Znll - //~| ERROR failed type test + //~| ERROR `T` does not outlive } fn outlives_region<'a, 'b, T>(x: Box) -> Box diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr index 721896a93ff..37ebc38da4d 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr @@ -25,7 +25,7 @@ note: External requirements = note: number of external vids: 3 = note: where T: '_#2r -error: failed type test: TypeTest { generic_kind: T/#1, lower_bound: '_#4r, point: bb0[5], span: $DIR/ty-param-closure-outlives-from-return-type.rs:37:23: 37:28, test: IsOutlivedByAnyRegionIn(['_#2r]) } +error: `T` does not outlive `'_#4r` --> $DIR/ty-param-closure-outlives-from-return-type.rs:37:23 | 37 | with_signature(x, |y| y) @@ -39,7 +39,7 @@ note: No external requirements 28 | | T: Debug, 29 | | { ... | -39 | | //~| ERROR failed type test +39 | | //~| ERROR `T` does not outlive 40 | | } | |_^ | @@ -48,7 +48,7 @@ note: No external requirements T ] -error: failed type test: TypeTest { generic_kind: T/#2, lower_bound: '_#4r, point: bb0[3], span: $DIR/ty-param-closure-outlives-from-return-type.rs:53:5: 53:6, test: IsOutlivedByAnyRegionIn(['_#2r, '_#3r]) } +error: `T` does not outlive `'_#4r` --> $DIR/ty-param-closure-outlives-from-return-type.rs:53:5 | 53 | x diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs index 54f7b4fa50d..beed1a740ea 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs @@ -36,7 +36,7 @@ where #[rustc_regions] fn no_region<'a, T>(a: Cell<&'a ()>, b: T) { with_signature(a, b, |x, y| { - //~^ ERROR failed type test + //~^ ERROR `T` does not outlive // // See `correct_region`, which explains the point of this // test. The only difference is that, in the case of this @@ -74,7 +74,7 @@ where T: 'b, { with_signature(a, b, |x, y| { - //~^ ERROR failed type test + //~^ ERROR `T` does not outlive // See `correct_region` require(&x, &y) //~^ WARNING not reporting region error due to -Znll diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr index 748333badce..78445eb47c3 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr @@ -15,7 +15,7 @@ note: External requirements | 38 | with_signature(a, b, |x, y| { | __________________________^ -39 | | //~^ ERROR failed type test +39 | | //~^ ERROR `T` does not outlive 40 | | // 41 | | // See `correct_region`, which explains the point of this ... | @@ -58,7 +58,7 @@ note: External requirements | 76 | with_signature(a, b, |x, y| { | __________________________^ -77 | | //~^ ERROR failed type test +77 | | //~^ ERROR `T` does not outlive 78 | | // See `correct_region` 79 | | require(&x, &y) 80 | | //~^ WARNING not reporting region error due to -Znll @@ -94,12 +94,12 @@ note: External requirements = note: number of external vids: 4 = note: where T: '_#3r -error: failed type test: TypeTest { generic_kind: T/#0, lower_bound: '_#3r, point: bb0[5], span: $DIR/ty-param-closure-outlives-from-where-clause.rs:38:26: 47:6, test: IsOutlivedByAnyRegionIn(['_#2r]) } +error: `T` does not outlive `'_#3r` --> $DIR/ty-param-closure-outlives-from-where-clause.rs:38:26 | 38 | with_signature(a, b, |x, y| { | __________________________^ -39 | | //~^ ERROR failed type test +39 | | //~^ ERROR `T` does not outlive 40 | | // 41 | | // See `correct_region`, which explains the point of this ... | @@ -112,7 +112,7 @@ note: No external requirements | 37 | / fn no_region<'a, T>(a: Cell<&'a ()>, b: T) { 38 | | with_signature(a, b, |x, y| { -39 | | //~^ ERROR failed type test +39 | | //~^ ERROR `T` does not outlive 40 | | // ... | 47 | | }) @@ -140,12 +140,12 @@ note: No external requirements T ] -error: failed type test: TypeTest { generic_kind: T/#1, lower_bound: '_#5r, point: bb0[5], span: $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26: 81:6, test: IsOutlivedByAnyRegionIn(['_#1r, '_#3r]) } +error: `T` does not outlive `'_#5r` --> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26 | 76 | with_signature(a, b, |x, y| { | __________________________^ -77 | | //~^ ERROR failed type test +77 | | //~^ ERROR `T` does not outlive 78 | | // See `correct_region` 79 | | require(&x, &y) 80 | | //~^ WARNING not reporting region error due to -Znll diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn-body.rs b/src/test/ui/nll/ty-outlives/ty-param-fn-body.rs index 42e62b23896..a1e636cbc44 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-fn-body.rs +++ b/src/test/ui/nll/ty-outlives/ty-param-fn-body.rs @@ -29,7 +29,7 @@ fn region_within_body(t: T) { fn region_static<'a, T>(cell: Cell<&'a usize>, t: T) { outlives(cell, t) //~^ WARNING not reporting region error due to -Znll - //~| ERROR failed type test + //~| ERROR `T` does not outlive } fn outlives<'a, T>(x: Cell<&'a usize>, y: T) diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr b/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr index 3cc335bb29d..bbe55c52b6e 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr @@ -4,7 +4,7 @@ warning: not reporting region error due to -Znll 30 | outlives(cell, t) | ^^^^^^^^ -error: failed type test: TypeTest { generic_kind: T/#0, lower_bound: '_#4r, point: bb0[4], span: $DIR/ty-param-fn-body.rs:30:5: 30:22, test: IsOutlivedByAnyRegionIn(['_#2r]) } +error: `T` does not outlive `'_#4r` --> $DIR/ty-param-fn-body.rs:30:5 | 30 | outlives(cell, t) diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn.rs b/src/test/ui/nll/ty-outlives/ty-param-fn.rs index c6547ae68fa..76783af4ceb 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-fn.rs +++ b/src/test/ui/nll/ty-outlives/ty-param-fn.rs @@ -21,7 +21,7 @@ where { x //~^ WARNING not reporting region error due to -Znll - //~| ERROR failed type test + //~| ERROR `T` does not outlive } fn correct_region<'a, T>(x: Box) -> Box @@ -37,7 +37,7 @@ where { x //~^ WARNING not reporting region error due to -Znll - //~| ERROR failed type test + //~| ERROR `T` does not outlive } fn outlives_region<'a, 'b, T>(x: Box) -> Box diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn.stderr b/src/test/ui/nll/ty-outlives/ty-param-fn.stderr index 426bece3e9d..02c4ebbd5ac 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-fn.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-fn.stderr @@ -10,13 +10,13 @@ warning: not reporting region error due to -Znll 38 | x | ^ -error: failed type test: TypeTest { generic_kind: T/#1, lower_bound: '_#3r, point: bb0[3], span: $DIR/ty-param-fn.rs:22:5: 22:6, test: IsOutlivedByAnyRegionIn(['_#2r]) } +error: `T` does not outlive `'_#3r` --> $DIR/ty-param-fn.rs:22:5 | 22 | x | ^ -error: failed type test: TypeTest { generic_kind: T/#2, lower_bound: '_#4r, point: bb0[3], span: $DIR/ty-param-fn.rs:38:5: 38:6, test: IsOutlivedByAnyRegionIn(['_#2r, '_#3r]) } +error: `T` does not outlive `'_#4r` --> $DIR/ty-param-fn.rs:38:5 | 38 | x -- cgit 1.4.1-3-g733a5