summaryrefslogtreecommitdiffstats
path: root/src/test/ui/nll/ty-outlives
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/ui/nll/ty-outlives')
-rw-r--r--src/test/ui/nll/ty-outlives/impl-trait-captures.rs15
-rw-r--r--src/test/ui/nll/ty-outlives/impl-trait-captures.stderr16
-rw-r--r--src/test/ui/nll/ty-outlives/impl-trait-outlives.rs38
-rw-r--r--src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr25
-rw-r--r--src/test/ui/nll/ty-outlives/issue-53789-1.rs87
-rw-r--r--src/test/ui/nll/ty-outlives/issue-53789-2.rs249
-rw-r--r--src/test/ui/nll/ty-outlives/issue-55756.rs37
-rw-r--r--src/test/ui/nll/ty-outlives/projection-body.rs27
-rw-r--r--src/test/ui/nll/ty-outlives/projection-implied-bounds.rs40
-rw-r--r--src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr14
-rw-r--r--src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs55
-rw-r--r--src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr132
-rw-r--r--src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs40
-rw-r--r--src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr21
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-closure.rs83
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr167
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs84
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr169
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs88
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr130
-rw-r--r--src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs112
-rw-r--r--src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr260
-rw-r--r--src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.rs34
-rw-r--r--src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr12
-rw-r--r--src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.rs25
-rw-r--r--src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.stderr12
-rw-r--r--src/test/ui/nll/ty-outlives/projection-where-clause-env.rs28
-rw-r--r--src/test/ui/nll/ty-outlives/projection-where-clause-none.rs24
-rw-r--r--src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr14
-rw-r--r--src/test/ui/nll/ty-outlives/projection-where-clause-trait.rs25
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.rs39
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr65
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs53
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr53
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs83
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr151
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-fn-body.rs27
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr14
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-fn.rs36
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-fn.stderr25
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-implied-bounds.rs28
-rw-r--r--src/test/ui/nll/ty-outlives/wf-unreachable.rs52
-rw-r--r--src/test/ui/nll/ty-outlives/wf-unreachable.stderr73
43 files changed, 2762 insertions, 0 deletions
diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.rs b/src/test/ui/nll/ty-outlives/impl-trait-captures.rs
new file mode 100644
index 000000000..67b31b8bc
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.rs
@@ -0,0 +1,15 @@
+// compile-flags:-Zverbose
+
+#![allow(warnings)]
+
+trait Foo<'a> {
+}
+
+impl<'a, T> Foo<'a> for T { }
+
+fn foo<'a, T>(x: &T) -> impl Foo<'a> {
+ x
+ //~^ ERROR captures lifetime that does not appear in bounds
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
new file mode 100644
index 000000000..330c6fafa
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
@@ -0,0 +1,16 @@
+error[E0700]: hidden type for `Opaque(DefId(0:11 ~ impl_trait_captures[1afc]::foo::{opaque#0}), [ReStatic, T, ReEarlyBound(0, 'a)])` captures lifetime that does not appear in bounds
+ --> $DIR/impl-trait-captures.rs:11:5
+ |
+LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
+ | -- hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:13 ~ impl_trait_captures[1afc]::foo::'_), '_)) T` captures the anonymous lifetime defined here
+LL | x
+ | ^
+ |
+help: to declare that the `impl Trait` captures `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:13 ~ impl_trait_captures[1afc]::foo::'_), '_))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:13 ~ impl_trait_captures[1afc]::foo::'_), '_))` lifetime bound
+ |
+LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:13 ~ impl_trait_captures[1afc]::foo::'_), '_)) {
+ | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
diff --git a/src/test/ui/nll/ty-outlives/impl-trait-outlives.rs b/src/test/ui/nll/ty-outlives/impl-trait-outlives.rs
new file mode 100644
index 000000000..68ccb51fc
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/impl-trait-outlives.rs
@@ -0,0 +1,38 @@
+// compile-flags:-Zverbose
+
+#![allow(warnings)]
+
+use std::fmt::Debug;
+
+fn no_region<'a, T>(x: Box<T>) -> impl Debug + 'a
+where
+ T: Debug,
+{
+ x
+ //~^ ERROR the parameter type `T` may not live long enough [E0309]
+}
+
+fn correct_region<'a, T>(x: Box<T>) -> impl Debug + 'a
+where
+ T: 'a + Debug,
+{
+ x
+}
+
+fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
+where
+ T: 'b + Debug,
+{
+ x
+ //~^ ERROR the parameter type `T` may not live long enough [E0309]
+}
+
+fn outlives_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
+where
+ T: 'b + Debug,
+ 'b: 'a,
+{
+ x
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr b/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr
new file mode 100644
index 000000000..64b08a9b3
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr
@@ -0,0 +1,25 @@
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/impl-trait-outlives.rs:11:5
+ |
+LL | x
+ | ^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: Debug + 'a,
+ | ++++
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/impl-trait-outlives.rs:26:5
+ |
+LL | x
+ | ^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: 'b + Debug + 'a,
+ | ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/nll/ty-outlives/issue-53789-1.rs b/src/test/ui/nll/ty-outlives/issue-53789-1.rs
new file mode 100644
index 000000000..a5201d4bb
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/issue-53789-1.rs
@@ -0,0 +1,87 @@
+// Regression test for #53789.
+//
+// check-pass
+
+use std::collections::BTreeMap;
+
+trait ValueTree {
+ type Value;
+}
+
+trait Strategy {
+ type Value: ValueTree;
+}
+
+type StrategyFor<A> = StrategyType<'static, A>;
+type StrategyType<'a, A> = <A as Arbitrary<'a>>::Strategy;
+
+impl<K: ValueTree, V: ValueTree> Strategy for (K, V) {
+ type Value = TupleValueTree<(K, V)>;
+}
+
+impl<K: ValueTree, V: ValueTree> ValueTree for TupleValueTree<(K, V)> {
+ type Value = BTreeMapValueTree<K, V>;
+}
+
+struct TupleValueTree<T> {
+ tree: T,
+}
+
+struct BTreeMapStrategy<K, V>(std::marker::PhantomData<(K, V)>)
+where
+ K: Strategy,
+ V: Strategy;
+
+struct BTreeMapValueTree<K, V>(std::marker::PhantomData<(K, V)>)
+where
+ K: ValueTree,
+ V: ValueTree;
+
+impl<K, V> Strategy for BTreeMapStrategy<K, V>
+where
+ K: Strategy,
+ V: Strategy,
+{
+ type Value = BTreeMapValueTree<K::Value, V::Value>;
+}
+
+impl<K, V> ValueTree for BTreeMapValueTree<K, V>
+where
+ K: ValueTree,
+ V: ValueTree,
+{
+ type Value = BTreeMap<K::Value, V::Value>;
+}
+
+trait Arbitrary<'a>: Sized {
+ fn arbitrary_with(args: Self::Parameters) -> Self::Strategy;
+ type Parameters;
+ type Strategy: Strategy<Value = Self::ValueTree>;
+ type ValueTree: ValueTree<Value = Self>;
+}
+
+impl<'a, A, B> Arbitrary<'a> for BTreeMap<A, B>
+where
+ A: Arbitrary<'static>,
+ B: Arbitrary<'static>,
+ StrategyFor<A>: 'static,
+ StrategyFor<B>: 'static,
+{
+ type ValueTree = <Self::Strategy as Strategy>::Value;
+ type Parameters = (A::Parameters, B::Parameters);
+ type Strategy = BTreeMapStrategy<A::Strategy, B::Strategy>;
+ fn arbitrary_with(args: Self::Parameters) -> BTreeMapStrategy<A::Strategy, B::Strategy> {
+ let (a, b) = args;
+ btree_map(any_with::<A>(a), any_with::<B>(b))
+ }
+}
+
+fn btree_map<K: Strategy + 'static, V: Strategy>(key: K, value: V) -> BTreeMapStrategy<K, V> {
+ unimplemented!()
+}
+
+fn any_with<'a, A: Arbitrary<'a>>(args: A::Parameters) -> StrategyType<'a, A> {
+ unimplemented!()
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/ty-outlives/issue-53789-2.rs b/src/test/ui/nll/ty-outlives/issue-53789-2.rs
new file mode 100644
index 000000000..5109a0e4a
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/issue-53789-2.rs
@@ -0,0 +1,249 @@
+// Regression test for #53789.
+//
+// check-pass
+
+use std::cmp::Ord;
+use std::collections::BTreeMap;
+use std::ops::Range;
+
+macro_rules! valuetree {
+ () => {
+ type ValueTree = <Self::Strategy as $crate::Strategy>::Value;
+ };
+}
+
+macro_rules! product_unpack {
+ ($factor: pat) => {
+ ($factor,)
+ };
+ ($($factor: pat),*) => {
+ ( $( $factor ),* )
+ };
+ ($($factor: pat),*,) => {
+ ( $( $factor ),* )
+ };
+}
+
+macro_rules! product_type {
+ ($factor: ty) => {
+ ($factor,)
+ };
+ ($($factor: ty),*) => {
+ ( $( $factor, )* )
+ };
+ ($($factor: ty),*,) => {
+ ( $( $factor, )* )
+ };
+}
+
+macro_rules! default {
+ ($type: ty, $val: expr) => {
+ impl Default for $type {
+ fn default() -> Self {
+ $val.into()
+ }
+ }
+ };
+}
+
+// Pervasive internal sugar
+macro_rules! mapfn {
+ ($(#[$meta:meta])* [$($vis:tt)*]
+ fn $name:ident[$($gen:tt)*]($parm:ident: $input:ty) -> $output:ty {
+ $($body:tt)*
+ }) => {
+ $(#[$meta])*
+ #[derive(Clone, Copy)]
+ $($vis)* struct $name;
+ impl $($gen)* statics::MapFn<$input> for $name {
+ type Output = $output;
+ }
+ }
+}
+
+macro_rules! opaque_strategy_wrapper {
+ ($(#[$smeta:meta])* pub struct $stratname:ident
+ [$($sgen:tt)*][$($swhere:tt)*]
+ ($innerstrat:ty) -> $stratvtty:ty;
+
+ $(#[$vmeta:meta])* pub struct $vtname:ident
+ [$($vgen:tt)*][$($vwhere:tt)*]
+ ($innervt:ty) -> $actualty:ty;
+ ) => {
+ $(#[$smeta])* struct $stratname $($sgen)* (std::marker::PhantomData<(K, V)>)
+ $($swhere)*;
+
+ $(#[$vmeta])* struct $vtname $($vgen)* ($innervt) $($vwhere)*;
+
+ impl $($sgen)* Strategy for $stratname $($sgen)* $($swhere)* {
+ type Value = $stratvtty;
+ }
+
+ impl $($vgen)* ValueTree for $vtname $($vgen)* $($vwhere)* {
+ type Value = $actualty;
+ }
+ }
+}
+
+trait ValueTree {
+ type Value;
+}
+
+trait Strategy {
+ type Value: ValueTree;
+}
+
+#[derive(Clone)]
+struct VecStrategy<T: Strategy> {
+ element: T,
+ size: Range<usize>,
+}
+
+fn vec<T: Strategy>(element: T, size: Range<usize>) -> VecStrategy<T> {
+ VecStrategy { element: element, size: size }
+}
+
+type ValueFor<S> = <<S as Strategy>::Value as ValueTree>::Value;
+
+trait Arbitrary<'a>: Sized {
+ fn arbitrary_with(args: Self::Parameters) -> Self::Strategy;
+
+ type Parameters: Default;
+ type Strategy: Strategy<Value = Self::ValueTree>;
+ type ValueTree: ValueTree<Value = Self>;
+}
+
+type StrategyFor<A> = StrategyType<'static, A>;
+type StrategyType<'a, A> = <A as Arbitrary<'a>>::Strategy;
+
+//#[derive(Clone, PartialEq, Eq, Hash, Debug, From, Into)]
+struct SizeBounds(Range<usize>);
+default!(SizeBounds, 0..100);
+
+impl From<Range<usize>> for SizeBounds {
+ fn from(high: Range<usize>) -> Self {
+ unimplemented!()
+ }
+}
+
+impl From<SizeBounds> for Range<usize> {
+ fn from(high: SizeBounds) -> Self {
+ unimplemented!()
+ }
+}
+
+fn any_with<'a, A: Arbitrary<'a>>(args: A::Parameters) -> StrategyType<'a, A> {
+ unimplemented!()
+}
+
+impl<K: ValueTree, V: ValueTree> Strategy for (K, V)
+where
+ <K as ValueTree>::Value: Ord,
+{
+ type Value = TupleValueTree<(K, V)>;
+}
+
+impl<K: ValueTree, V: ValueTree> ValueTree for TupleValueTree<(K, V)>
+where
+ <K as ValueTree>::Value: Ord,
+{
+ type Value = BTreeMapValueTree<K, V>;
+}
+
+#[derive(Clone)]
+struct VecValueTree<T: ValueTree> {
+ elements: Vec<T>,
+}
+
+#[derive(Clone, Copy)]
+struct TupleValueTree<T> {
+ tree: T,
+}
+
+opaque_strategy_wrapper! {
+ #[derive(Clone)]
+ pub struct BTreeMapStrategy[<K, V>]
+ [where K : Strategy, V : Strategy, ValueFor<K> : Ord](
+ statics::Filter<statics::Map<VecStrategy<(K,V)>,
+ VecToBTreeMap>, MinSize>)
+ -> BTreeMapValueTree<K::Value, V::Value>;
+
+ #[derive(Clone)]
+ pub struct BTreeMapValueTree[<K, V>]
+ [where K : ValueTree, V : ValueTree, K::Value : Ord](
+ statics::Filter<statics::Map<VecValueTree<TupleValueTree<(K, V)>>,
+ VecToBTreeMap>, MinSize>)
+ -> BTreeMap<K::Value, V::Value>;
+}
+
+type RangedParams2<A, B> = product_type![SizeBounds, A, B];
+
+impl<'a, A, B> Arbitrary<'a> for BTreeMap<A, B>
+where
+ A: Arbitrary<'static> + Ord,
+ B: Arbitrary<'static>,
+ StrategyFor<A>: 'static,
+ StrategyFor<B>: 'static,
+{
+ valuetree!();
+ type Parameters = RangedParams2<A::Parameters, B::Parameters>;
+ type Strategy = BTreeMapStrategy<A::Strategy, B::Strategy>;
+ fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
+ let product_unpack![range, a, b] = args;
+ btree_map(any_with::<A>(a), any_with::<B>(b), range.into())
+ }
+}
+
+#[derive(Clone, Copy)]
+struct MinSize(usize);
+
+mapfn! {
+ [] fn VecToBTreeMap[<K : Ord, V>]
+ (vec: Vec<(K, V)>) -> BTreeMap<K, V>
+ {
+ vec.into_iter().collect()
+ }
+}
+
+fn btree_map<K: Strategy + 'static, V: Strategy + 'static>(
+ key: K,
+ value: V,
+ size: Range<usize>,
+) -> BTreeMapStrategy<K, V>
+where
+ ValueFor<K>: Ord,
+{
+ unimplemented!()
+}
+
+mod statics {
+ pub(super) trait MapFn<T> {
+ type Output;
+ }
+
+ #[derive(Clone)]
+ pub struct Filter<S, F> {
+ source: S,
+ fun: F,
+ }
+
+ impl<S, F> Filter<S, F> {
+ pub fn new(source: S, whence: String, filter: F) -> Self {
+ unimplemented!()
+ }
+ }
+
+ #[derive(Clone)]
+ pub struct Map<S, F> {
+ source: S,
+ fun: F,
+ }
+
+ impl<S, F> Map<S, F> {
+ pub fn new(source: S, fun: F) -> Self {
+ unimplemented!()
+ }
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/issue-55756.rs b/src/test/ui/nll/ty-outlives/issue-55756.rs
new file mode 100644
index 000000000..e1a3bc3c4
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/issue-55756.rs
@@ -0,0 +1,37 @@
+// Regression test for #55756.
+//
+// In this test, the result of `self.callee` is a projection `<D as
+// Database<'?0>>::Guard`. As it may contain a destructor, the dropck
+// rules require that this type outlivess the scope of `state`. Unfortunately,
+// our region inference is not smart enough to figure out how to
+// translate a requirement like
+//
+// <D as Database<'0>>::guard: 'r
+//
+// into a requirement that `'0: 'r` -- in particular, it fails to do
+// so because it *also* knows that `<D as Database<'a>>::Guard: 'a`
+// from the trait definition. Faced with so many choices, the current
+// solver opts to do nothing.
+//
+// Fixed by tweaking the solver to recognize that the constraint from
+// the environment duplicates one from the trait.
+//
+// check-pass
+
+#![crate_type="lib"]
+
+pub trait Database<'a> {
+ type Guard: 'a;
+}
+
+pub struct Stateful<'a, D: 'a>(&'a D);
+
+impl<'b, D: for <'a> Database<'a>> Stateful<'b, D> {
+ pub fn callee<'a>(&'a self) -> <D as Database<'a>>::Guard {
+ unimplemented!()
+ }
+ pub fn caller<'a>(&'a self) -> <D as Database<'a>>::Guard {
+ let state = self.callee();
+ unimplemented!()
+ }
+}
diff --git a/src/test/ui/nll/ty-outlives/projection-body.rs b/src/test/ui/nll/ty-outlives/projection-body.rs
new file mode 100644
index 000000000..b03a539eb
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-body.rs
@@ -0,0 +1,27 @@
+// Test that when we infer the lifetime to a subset of the fn body, it
+// works out.
+//
+// check-pass
+
+trait MyTrait<'a> {
+ type Output;
+}
+
+fn foo1<T>()
+where
+ for<'x> T: MyTrait<'x>,
+{
+ // Here the region `'c` in `<T as MyTrait<'c>>::Output` will be
+ // inferred to a subset of the fn body.
+ let x = bar::<T::Output>();
+ drop(x);
+}
+
+fn bar<'a, T>() -> &'a ()
+where
+ T: 'a,
+{
+ &()
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/projection-implied-bounds.rs b/src/test/ui/nll/ty-outlives/projection-implied-bounds.rs
new file mode 100644
index 000000000..e1dac0824
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-implied-bounds.rs
@@ -0,0 +1,40 @@
+// Test that we can deduce when projections like `T::Item` outlive the
+// function body. Test that this does not imply that `T: 'a` holds.
+
+// compile-flags:-Zverbose
+
+use std::cell::Cell;
+
+fn twice<F, T>(mut value: T, mut f: F)
+where
+ F: FnMut(&T, Cell<&Option<T::Item>>),
+ T: Iterator,
+{
+ let mut n = value.next();
+ f(&value, Cell::new(&n));
+ f(&value, Cell::new(&n));
+}
+
+fn generic1<T: Iterator>(value: T) {
+ // No error here:
+ twice(value, |value_ref, item| invoke1(item));
+}
+
+fn invoke1<'a, T>(x: Cell<&'a Option<T>>)
+where
+ T: 'a,
+{
+}
+
+fn generic2<T: Iterator>(value: T) {
+ twice(value, |value_ref, item| invoke2(value_ref, item));
+ //~^ ERROR the parameter type `T` may not live long enough
+}
+
+fn invoke2<'a, T, U>(a: &T, b: Cell<&'a Option<U>>)
+where
+ T: 'a,
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr b/src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr
new file mode 100644
index 000000000..3b9b2956c
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr
@@ -0,0 +1,14 @@
+error[E0310]: the parameter type `T` may not live long enough
+ --> $DIR/projection-implied-bounds.rs:30:18
+ |
+LL | twice(value, |value_ref, item| invoke2(value_ref, item));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn generic2<T: Iterator + 'static>(value: T) {
+ | +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0310`.
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 000000000..2d9c008c7
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs
@@ -0,0 +1,55 @@
+// compile-flags:-Zverbose
+
+// Tests closures that propagate an outlives relationship to their
+// creator where the subject is a projection with no regions (`<T as
+// Iterator>::Item`, to be exact).
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+trait Anything { }
+
+impl<T> Anything for T { }
+
+fn with_signature<'a, T, F>(x: Box<T>, op: F) -> Box<dyn Anything + 'a>
+ where F: FnOnce(Box<T>) -> Box<dyn Anything + 'a>
+{
+ op(x)
+}
+
+#[rustc_regions]
+fn no_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+where
+ T: Iterator,
+{
+ with_signature(x, |mut y| Box::new(y.next()))
+ //~^ ERROR the associated type `<T as Iterator>::Item` may not live long enough
+}
+
+#[rustc_regions]
+fn correct_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+where
+ T: 'a + Iterator,
+{
+ with_signature(x, |mut y| Box::new(y.next()))
+}
+
+#[rustc_regions]
+fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+where
+ T: 'b + Iterator,
+{
+ with_signature(x, |mut y| Box::new(y.next()))
+ //~^ ERROR the associated type `<T as Iterator>::Item` may not live long enough
+}
+
+#[rustc_regions]
+fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+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 000000000..feab24769
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr
@@ -0,0 +1,132 @@
+note: external requirements
+ --> $DIR/projection-no-regions-closure.rs:25:23
+ |
+LL | with_signature(x, |mut y| Box::new(y.next()))
+ | ^^^^^^^
+ |
+ = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>,
+ (),
+ ]
+ = note: number of external vids: 3
+ = note: where <T as std::iter::Iterator>::Item: '_#2r
+
+note: no external requirements
+ --> $DIR/projection-no-regions-closure.rs:21:1
+ |
+LL | / fn no_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+LL | | where
+LL | | T: Iterator,
+LL | | {
+LL | | with_signature(x, |mut y| Box::new(y.next()))
+LL | |
+LL | | }
+ | |_^
+ |
+ = note: defining type: no_region::<'_#1r, T>
+
+error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough
+ --> $DIR/projection-no-regions-closure.rs:25:23
+ |
+LL | with_signature(x, |mut y| Box::new(y.next()))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
+ = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
+
+note: external requirements
+ --> $DIR/projection-no-regions-closure.rs:34:23
+ |
+LL | with_signature(x, |mut y| Box::new(y.next()))
+ | ^^^^^^^
+ |
+ = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>,
+ (),
+ ]
+ = note: number of external vids: 3
+ = note: where <T as std::iter::Iterator>::Item: '_#2r
+
+note: no external requirements
+ --> $DIR/projection-no-regions-closure.rs:30:1
+ |
+LL | / fn correct_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+LL | | where
+LL | | T: 'a + Iterator,
+LL | | {
+LL | | with_signature(x, |mut y| Box::new(y.next()))
+LL | | }
+ | |_^
+ |
+ = note: defining type: correct_region::<'_#1r, T>
+
+note: external requirements
+ --> $DIR/projection-no-regions-closure.rs:42:23
+ |
+LL | with_signature(x, |mut y| Box::new(y.next()))
+ | ^^^^^^^
+ |
+ = note: defining type: wrong_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>,
+ (),
+ ]
+ = note: number of external vids: 4
+ = note: where <T as std::iter::Iterator>::Item: '_#3r
+
+note: no external requirements
+ --> $DIR/projection-no-regions-closure.rs:38:1
+ |
+LL | / fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+LL | | where
+LL | | T: 'b + Iterator,
+LL | | {
+LL | | with_signature(x, |mut y| Box::new(y.next()))
+LL | |
+LL | | }
+ | |_^
+ |
+ = note: defining type: wrong_region::<'_#1r, '_#2r, T>
+
+error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough
+ --> $DIR/projection-no-regions-closure.rs:42:23
+ |
+LL | with_signature(x, |mut y| Box::new(y.next()))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
+ = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
+
+note: external requirements
+ --> $DIR/projection-no-regions-closure.rs:52:23
+ |
+LL | with_signature(x, |mut y| Box::new(y.next()))
+ | ^^^^^^^
+ |
+ = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>,
+ (),
+ ]
+ = note: number of external vids: 4
+ = note: where <T as std::iter::Iterator>::Item: '_#3r
+
+note: no external requirements
+ --> $DIR/projection-no-regions-closure.rs:47:1
+ |
+LL | / fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+LL | | where
+LL | | T: 'b + Iterator,
+LL | | 'b: 'a,
+LL | | {
+LL | | with_signature(x, |mut y| Box::new(y.next()))
+LL | | }
+ | |_^
+ |
+ = note: defining type: outlives_region::<'_#1r, '_#2r, T>
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
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 000000000..a10a0366a
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs
@@ -0,0 +1,40 @@
+// compile-flags:-Zverbose
+
+#![allow(warnings)]
+
+trait Anything { }
+
+impl<T> Anything for T { }
+
+fn no_region<'a, T>(mut x: T) -> Box<dyn Anything + 'a>
+where
+ T: Iterator,
+{
+ Box::new(x.next())
+ //~^ ERROR the associated type `<T as Iterator>::Item` may not live long enough
+}
+
+fn correct_region<'a, T>(mut x: T) -> Box<dyn Anything + 'a>
+where
+ T: 'a + Iterator,
+{
+ Box::new(x.next())
+}
+
+fn wrong_region<'a, 'b, T>(mut x: T) -> Box<dyn Anything + 'a>
+where
+ T: 'b + Iterator,
+{
+ Box::new(x.next())
+ //~^ ERROR the associated type `<T as Iterator>::Item` may not live long enough
+}
+
+fn outlives_region<'a, 'b, T>(mut x: T) -> Box<dyn Anything + 'a>
+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 000000000..e0ff544fe
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr
@@ -0,0 +1,21 @@
+error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough
+ --> $DIR/projection-no-regions-fn.rs:13:5
+ |
+LL | Box::new(x.next())
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
+ = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
+
+error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough
+ --> $DIR/projection-no-regions-fn.rs:28:5
+ |
+LL | Box::new(x.next())
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
+ = note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
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 000000000..af361e990
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs
@@ -0,0 +1,83 @@
+// Test cases where we constrain `<T as Anything<'b>>::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:-Zverbose
+
+#![allow(warnings)]
+#![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));
+ //~^ ERROR the parameter type `T` may not live long enough
+ //~| ERROR
+}
+
+#[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));
+ //~^ ERROR the parameter type `T` may not live long enough
+ //~| ERROR
+}
+
+#[rustc_regions]
+fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b>,
+ T::AssocType: 'a,
+{
+ // We are projecting `<T as Anything<'b>>::AssocType`, and we know
+ // that this outlives `'a` because of the where-clause.
+
+ 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>,
+ 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 000000000..98063bd0a
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
@@ -0,0 +1,167 @@
+note: external requirements
+ --> $DIR/projection-one-region-closure.rs:45:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+ = note: number of external vids: 4
+ = note: where T: '_#2r
+ = note: where '_#1r: '_#2r
+
+note: no external requirements
+ --> $DIR/projection-one-region-closure.rs:41:1
+ |
+LL | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | {
+... |
+LL | |
+LL | | }
+ | |_^
+ |
+ = note: defining type: no_relationships_late::<'_#1r, T>
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/projection-one-region-closure.rs:45:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: Anything<'b> + 'a,
+ | ++++
+
+error: lifetime may not live long enough
+ --> $DIR/projection-one-region-closure.rs:45:39
+ |
+LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+note: external requirements
+ --> $DIR/projection-one-region-closure.rs:56:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ 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: no external requirements
+ --> $DIR/projection-one-region-closure.rs:51:1
+ |
+LL | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | 'a: 'a,
+... |
+LL | |
+LL | | }
+ | |_^
+ |
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/projection-one-region-closure.rs:56:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: Anything<'b> + 'a,
+ | ++++
+
+error: lifetime may not live long enough
+ --> $DIR/projection-one-region-closure.rs:56:39
+ |
+LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+note: external requirements
+ --> $DIR/projection-one-region-closure.rs:70:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 4
+ = note: where <T as Anything<ReEarlyBound(1, 'b)>>::AssocType: '_#3r
+
+note: no external requirements
+ --> $DIR/projection-one-region-closure.rs:62:1
+ |
+LL | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | T::AssocType: 'a,
+... |
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | | }
+ | |_^
+ |
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, T>
+
+note: external requirements
+ --> $DIR/projection-one-region-closure.rs:80:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ 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: no external requirements
+ --> $DIR/projection-one-region-closure.rs:74:1
+ |
+LL | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | T: 'a,
+... |
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | | }
+ | |_^
+ |
+ = note: defining type: elements_outlive::<'_#1r, '_#2r, T>
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
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 000000000..6f8513491
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs
@@ -0,0 +1,84 @@
+// Test cases where we constrain `<T as Anything<'b>>::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:-Zverbose
+
+#![allow(warnings)]
+#![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));
+ //~^ ERROR
+}
+
+#[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));
+ //~^ ERROR
+}
+
+#[rustc_regions]
+fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b>,
+ T::AssocType: 'a,
+{
+ // We are projecting `<T as Anything<'b>>::AssocType`, and we know
+ // that this outlives `'a` because of the where-clause.
+
+ 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-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
new file mode 100644
index 000000000..45e61bcbd
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
@@ -0,0 +1,169 @@
+note: external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:37:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+ = note: number of external vids: 4
+ = note: where '_#1r: '_#2r
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:33:1
+ |
+LL | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | {
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | |
+LL | | }
+ | |_^
+ |
+ = note: defining type: no_relationships_late::<'_#1r, T>
+
+error: lifetime may not live long enough
+ --> $DIR/projection-one-region-trait-bound-closure.rs:37:39
+ |
+LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+note: external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:47:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 4
+ = note: where '_#2r: '_#3r
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:42:1
+ |
+LL | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | 'a: 'a,
+... |
+LL | |
+LL | | }
+ | |_^
+ |
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>
+
+error: lifetime may not live long enough
+ --> $DIR/projection-one-region-trait-bound-closure.rs:47:39
+ |
+LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+note: external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:60:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 4
+ = note: where <T as Anything<ReEarlyBound(1, 'b)>>::AssocType: '_#3r
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:52:1
+ |
+LL | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | T::AssocType: 'a,
+... |
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | | }
+ | |_^
+ |
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, T>
+
+note: external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:69:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 4
+ = note: where '_#2r: '_#3r
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:64:1
+ |
+LL | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | 'b: 'a,
+LL | | {
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | | }
+ | |_^
+ |
+ = note: defining type: elements_outlive::<'_#1r, '_#2r, T>
+
+note: external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:81:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 3
+ = note: where '_#1r: '_#2r
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-closure.rs:73:1
+ |
+LL | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'a>,
+LL | | {
+... |
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | | }
+ | |_^
+ |
+ = note: defining type: one_region::<'_#1r, T>
+
+error: aborting due to 2 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 000000000..7c0a3bc72
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs
@@ -0,0 +1,88 @@
+// Test cases where we constrain `<T as Anything<'b>>::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:-Zverbose
+// check-pass
+
+#![allow(warnings)]
+#![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 `<T as Anything<'b>>::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 `<T as
+ // Anything<'?0>>::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 000000000..f2549205b
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr
@@ -0,0 +1,130 @@
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:36:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:32:1
+ |
+LL | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | {
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | | }
+ | |_^
+ |
+ = note: defining type: no_relationships_late::<'_#1r, T>
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:45:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:40:1
+ |
+LL | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | 'a: 'a,
+LL | | {
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | | }
+ | |_^
+ |
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:64:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:49:1
+ |
+LL | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | T::AssocType: 'a,
+... |
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | | }
+ | |_^
+ |
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, T>
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:73:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:68:1
+ |
+LL | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b>,
+LL | | 'b: 'a,
+LL | | {
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | | }
+ | |_^
+ |
+ = note: defining type: elements_outlive::<'_#1r, '_#2r, T>
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:85:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+ (),
+ ]
+
+note: no external requirements
+ --> $DIR/projection-one-region-trait-bound-static-closure.rs:77:1
+ |
+LL | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'a>,
+LL | | {
+... |
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | | }
+ | |_^
+ |
+ = note: defining type: one_region::<'_#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 000000000..7b4a3c03a
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs
@@ -0,0 +1,112 @@
+// Test cases where we constrain `<T as Anything<'a, 'b>>::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:-Zverbose
+
+#![allow(warnings)]
+#![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));
+ //~^ ERROR may not live long enough
+}
+
+#[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));
+ //~^ ERROR may not live long enough
+}
+
+#[rustc_regions]
+fn projection_outlives<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+where
+ T: Anything<'b, 'c>,
+ T::AssocType: 'a,
+{
+ // We are projecting `<T as Anything<'b>>::AssocType`, and we know
+ // that this outlives `'a` because of the where-clause.
+
+ with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[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));
+ //~^ ERROR lifetime may not live long enough
+}
+
+#[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 000000000..8e1b6fa2e
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
@@ -0,0 +1,260 @@
+note: external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:38:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+ = note: late-bound region is '_#4r
+ = note: number of external vids: 5
+ = note: where <T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType: '_#3r
+
+note: no external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:34:1
+ |
+LL | / fn no_relationships_late<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b, 'c>,
+LL | | {
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | |
+LL | | }
+ | |_^
+ |
+ = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>
+
+error[E0309]: the associated type `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType` may not live long enough
+ --> $DIR/projection-two-region-trait-bound-closure.rs:38:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType: 'a`...
+ = note: ...so that the type `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType` will meet its required lifetime bounds
+
+note: external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:48:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 5
+ = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
+
+note: no external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:43:1
+ |
+LL | / fn no_relationships_early<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b, 'c>,
+LL | | 'a: 'a,
+... |
+LL | |
+LL | | }
+ | |_^
+ |
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>
+
+error[E0309]: the associated type `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType` may not live long enough
+ --> $DIR/projection-two-region-trait-bound-closure.rs:48:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: 'a`...
+ = note: ...so that the type `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType` will meet its required lifetime bounds
+
+note: external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:61:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 5
+ = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
+
+note: no external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:53:1
+ |
+LL | / fn projection_outlives<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b, 'c>,
+LL | | T::AssocType: 'a,
+... |
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | | }
+ | |_^
+ |
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, '_#3r, T>
+
+note: external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:70:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: elements_outlive1::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 5
+ = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
+
+note: no external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:65:1
+ |
+LL | / fn elements_outlive1<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b, 'c>,
+LL | | 'b: 'a,
+LL | | {
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | | }
+ | |_^
+ |
+ = note: defining type: elements_outlive1::<'_#1r, '_#2r, '_#3r, T>
+
+note: external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:79:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: elements_outlive2::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 5
+ = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
+
+note: no external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:74:1
+ |
+LL | / fn elements_outlive2<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b, 'c>,
+LL | | 'c: 'a,
+LL | | {
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | | }
+ | |_^
+ |
+ = note: defining type: elements_outlive2::<'_#1r, '_#2r, '_#3r, T>
+
+note: external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:87:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: two_regions::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+ = note: number of external vids: 4
+ = note: where <T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(0, 'b)>>::AssocType: '_#2r
+
+note: no external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:83:1
+ |
+LL | / fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b, 'b>,
+LL | | {
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | |
+LL | | }
+ | |_^
+ |
+ = note: defining type: two_regions::<'_#1r, T>
+
+error: lifetime may not live long enough
+ --> $DIR/projection-two-region-trait-bound-closure.rs:87:29
+ |
+LL | fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ closure body requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+note: external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:97:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: two_regions_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 4
+ = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(1, 'b)>>::AssocType: '_#3r
+
+note: no external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:92:1
+ |
+LL | / fn two_regions_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'b, 'b>,
+LL | | 'b: 'a,
+LL | | {
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | | }
+ | |_^
+ |
+ = note: defining type: two_regions_outlive::<'_#1r, '_#2r, T>
+
+note: external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:109:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^
+ |
+ = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 3
+ = note: where <T as Anything<ReEarlyBound(0, 'a), ReEarlyBound(0, 'a)>>::AssocType: '_#2r
+
+note: no external requirements
+ --> $DIR/projection-two-region-trait-bound-closure.rs:101:1
+ |
+LL | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
+LL | | where
+LL | | T: Anything<'a, 'a>,
+LL | | {
+... |
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | | }
+ | |_^
+ |
+ = note: defining type: one_region::<'_#1r, T>
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.rs b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.rs
new file mode 100644
index 000000000..dce88b88c
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.rs
@@ -0,0 +1,34 @@
+// Test that we are able to establish that `<T as
+// MyTrait<'a>>::Output` outlives `'b` here. We need to prove however
+// that `<T as MyTrait<'a>>::Output` outlives `'a`, so we also have to
+// prove that `'b: 'a`.
+
+trait MyTrait<'a> {
+ type Output;
+}
+
+fn foo1<'a, 'b, T>() -> &'a ()
+where
+ T: MyTrait<'a>,
+ <T as MyTrait<'a>>::Output: 'b,
+{
+ bar::<T::Output>() //~ ERROR may not live long enough
+}
+
+fn foo2<'a, 'b, T>() -> &'a ()
+where
+ T: MyTrait<'a>,
+ <T as MyTrait<'a>>::Output: 'b,
+ 'b: 'a,
+{
+ bar::<T::Output>() // OK
+}
+
+fn bar<'a, T>() -> &'a ()
+where
+ T: 'a,
+{
+ &()
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr
new file mode 100644
index 000000000..b4435fe06
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr
@@ -0,0 +1,12 @@
+error[E0309]: the associated type `<T as MyTrait<'_>>::Output` may not live long enough
+ --> $DIR/projection-where-clause-env-wrong-bound.rs:15:5
+ |
+LL | bar::<T::Output>()
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as MyTrait<'_>>::Output: 'a`...
+ = note: ...so that the type `<T as MyTrait<'_>>::Output` will meet its required lifetime bounds
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.rs b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.rs
new file mode 100644
index 000000000..987148dce
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.rs
@@ -0,0 +1,25 @@
+// Test that if we need to prove that `<T as MyTrait<'a>>::Output:
+// 'a`, but we only know that `<T as MyTrait<'b>>::Output: 'a`, that
+// doesn't suffice.
+
+trait MyTrait<'a> {
+ type Output;
+}
+
+fn foo1<'a, 'b, T>() -> &'a ()
+where
+ for<'x> T: MyTrait<'x>,
+ <T as MyTrait<'b>>::Output: 'a,
+{
+ bar::<<T as MyTrait<'a>>::Output>()
+ //~^ ERROR the associated type `<T as MyTrait<'_>>::Output` may not live long enough
+}
+
+fn bar<'a, T>() -> &'a ()
+where
+ T: 'a,
+{
+ &()
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.stderr b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.stderr
new file mode 100644
index 000000000..ddeaf3c1f
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.stderr
@@ -0,0 +1,12 @@
+error[E0309]: the associated type `<T as MyTrait<'_>>::Output` may not live long enough
+ --> $DIR/projection-where-clause-env-wrong-lifetime.rs:14:5
+ |
+LL | bar::<<T as MyTrait<'a>>::Output>()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as MyTrait<'_>>::Output: 'a`...
+ = note: ...so that the type `<T as MyTrait<'_>>::Output` will meet its required lifetime bounds
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-env.rs b/src/test/ui/nll/ty-outlives/projection-where-clause-env.rs
new file mode 100644
index 000000000..a41116232
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-where-clause-env.rs
@@ -0,0 +1,28 @@
+// Test that when we have a `<T as MyTrait<'a>>::Output: 'a`
+// relationship in the environment we take advantage of it. In this
+// case, that means we **don't** have to prove that `T: 'a`.
+//
+// Regression test for #53121.
+//
+// check-pass
+
+trait MyTrait<'a> {
+ type Output;
+}
+
+fn foo<'a, T>() -> &'a ()
+where
+ T: MyTrait<'a>,
+ <T as MyTrait<'a>>::Output: 'a,
+{
+ bar::<T::Output>()
+}
+
+fn bar<'a, T>() -> &'a ()
+where
+ T: 'a,
+{
+ &()
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-none.rs b/src/test/ui/nll/ty-outlives/projection-where-clause-none.rs
new file mode 100644
index 000000000..bb201e5c0
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-where-clause-none.rs
@@ -0,0 +1,24 @@
+// Test that we are NOT able to establish that `<T as
+// MyTrait<'a>>::Output: 'a` outlives `'a` here -- we have only one
+// recourse, which is to prove that `T: 'a` and `'a: 'a`, but we don't
+// know that `T: 'a`.
+
+trait MyTrait<'a> {
+ type Output;
+}
+
+fn foo<'a, T>() -> &'a ()
+where
+ T: MyTrait<'a>,
+{
+ bar::<T::Output>() //~ ERROR the parameter type `T` may not live long enough
+}
+
+fn bar<'a, T>() -> &'a ()
+where
+ T: 'a,
+{
+ &()
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr b/src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr
new file mode 100644
index 000000000..0df44644d
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr
@@ -0,0 +1,14 @@
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/projection-where-clause-none.rs:14:5
+ |
+LL | bar::<T::Output>()
+ | ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: MyTrait<'a> + 'a,
+ | ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-trait.rs b/src/test/ui/nll/ty-outlives/projection-where-clause-trait.rs
new file mode 100644
index 000000000..1a40d3b4c
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-where-clause-trait.rs
@@ -0,0 +1,25 @@
+// Test that we are able to establish that `<T as
+// MyTrait<'a>>::Output: 'a` outlives `'a` (because the trait says
+// so).
+//
+// check-pass
+
+trait MyTrait<'a> {
+ type Output: 'a;
+}
+
+fn foo<'a, T>() -> &'a ()
+where
+ T: MyTrait<'a>,
+{
+ bar::<T::Output>()
+}
+
+fn bar<'a, T>() -> &'a ()
+where
+ T: 'a,
+{
+ &()
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.rs b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.rs
new file mode 100644
index 000000000..4d8380599
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.rs
@@ -0,0 +1,39 @@
+// compile-flags:-Zverbose
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// Invoke in such a way that the callee knows:
+//
+// - 'a: 'x
+//
+// and it must prove that `T: 'x`. Callee passes along `T: 'a`.
+fn twice<'a, F, T>(v: Cell<&'a ()>, value: T, mut f: F)
+where
+ F: for<'x> FnMut(Option<Cell<&'a &'x ()>>, &T),
+{
+ f(None, &value);
+ f(None, &value);
+}
+
+#[rustc_regions]
+fn generic<T>(value: T) {
+ let cell = Cell::new(&());
+ twice(cell, value, |a, b| invoke(a, b));
+}
+
+#[rustc_regions]
+fn generic_fail<'a, T>(cell: Cell<&'a ()>, value: T) {
+ twice(cell, value, |a, b| invoke(a, b));
+ //~^ ERROR the parameter type `T` may not live long enough
+}
+
+fn invoke<'a, 'x, T>(x: Option<Cell<&'x &'a ()>>, y: &T)
+where
+ T: 'x,
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
new file mode 100644
index 000000000..12c76d198
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
@@ -0,0 +1,65 @@
+note: external requirements
+ --> $DIR/ty-param-closure-approximate-lower-bound.rs:24:24
+ |
+LL | twice(cell, value, |a, b| invoke(a, b));
+ | ^^^^^^
+ |
+ = note: defining type: generic::<T>::{closure#0} with closure substs [
+ i16,
+ for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) T)),
+ (),
+ ]
+ = note: number of external vids: 2
+ = note: where T: '_#1r
+
+note: no external requirements
+ --> $DIR/ty-param-closure-approximate-lower-bound.rs:22:1
+ |
+LL | / fn generic<T>(value: T) {
+LL | | let cell = Cell::new(&());
+LL | | twice(cell, value, |a, b| invoke(a, b));
+LL | | }
+ | |_^
+ |
+ = note: defining type: generic::<T>
+
+note: external requirements
+ --> $DIR/ty-param-closure-approximate-lower-bound.rs:29:24
+ |
+LL | twice(cell, value, |a, b| invoke(a, b));
+ | ^^^^^^
+ |
+ = note: defining type: generic_fail::<T>::{closure#0} with closure substs [
+ i16,
+ for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) T)),
+ (),
+ ]
+ = note: late-bound region is '_#2r
+ = note: number of external vids: 3
+ = note: where T: '_#1r
+
+note: no external requirements
+ --> $DIR/ty-param-closure-approximate-lower-bound.rs:28:1
+ |
+LL | / fn generic_fail<'a, T>(cell: Cell<&'a ()>, value: T) {
+LL | | twice(cell, value, |a, b| invoke(a, b));
+LL | |
+LL | | }
+ | |_^
+ |
+ = note: defining type: generic_fail::<T>
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-closure-approximate-lower-bound.rs:29:24
+ |
+LL | twice(cell, value, |a, b| invoke(a, b));
+ | ^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn generic_fail<'a, T: 'a>(cell: Cell<&'a ()>, value: T) {
+ | ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
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 000000000..4343c3aee
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs
@@ -0,0 +1,53 @@
+// compile-flags:-Zverbose
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+
+use std::fmt::Debug;
+
+fn with_signature<'a, T, F>(x: Box<T>, op: F) -> Box<dyn Debug + 'a>
+ where F: FnOnce(Box<T>) -> Box<dyn Debug + 'a>
+{
+ op(x)
+}
+
+#[rustc_regions]
+fn no_region<'a, T>(x: Box<T>) -> Box<dyn Debug + 'a>
+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)
+ //~^ ERROR the parameter type `T` may not live long enough
+}
+
+fn correct_region<'a, T>(x: Box<T>) -> Box<Debug + 'a>
+where
+ T: 'a + Debug,
+{
+ x
+}
+
+fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
+where
+ T: 'b + Debug,
+{
+ x
+ //~^ ERROR the parameter type `T` may not live long enough
+}
+
+fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
+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 000000000..35741859d
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
@@ -0,0 +1,53 @@
+note: external requirements
+ --> $DIR/ty-param-closure-outlives-from-return-type.rs:26:23
+ |
+LL | with_signature(x, |y| y)
+ | ^^^
+ |
+ = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r)>,
+ (),
+ ]
+ = note: number of external vids: 3
+ = note: where T: '_#2r
+
+note: no external requirements
+ --> $DIR/ty-param-closure-outlives-from-return-type.rs:15:1
+ |
+LL | / fn no_region<'a, T>(x: Box<T>) -> Box<dyn Debug + 'a>
+LL | | where
+LL | | T: Debug,
+LL | | {
+... |
+LL | |
+LL | | }
+ | |_^
+ |
+ = note: defining type: no_region::<'_#1r, T>
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-closure-outlives-from-return-type.rs:26:23
+ |
+LL | with_signature(x, |y| y)
+ | ^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: Debug + 'a,
+ | ++++
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-closure-outlives-from-return-type.rs:41:5
+ |
+LL | x
+ | ^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: 'b + Debug + 'a,
+ | ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
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 000000000..d7702def3
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs
@@ -0,0 +1,83 @@
+// 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:-Zverbose
+
+#![allow(warnings)]
+#![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 the parameter type `T` may not live long enough
+ //
+ // 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)
+ })
+}
+
+#[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 the parameter type `T` may not live long enough
+ // See `correct_region`
+ require(&x, &y)
+ })
+}
+
+#[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 000000000..0261bc39e
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
@@ -0,0 +1,151 @@
+note: external requirements
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:27:26
+ |
+LL | with_signature(a, b, |x, y| {
+ | ^^^^^^
+ |
+ = note: defining type: no_region::<T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#1r ()>, T)),
+ (),
+ ]
+ = note: late-bound region is '_#2r
+ = note: number of external vids: 3
+ = note: where T: '_#1r
+
+note: no external requirements
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:26:1
+ |
+LL | / fn no_region<'a, T>(a: Cell<&'a ()>, b: T) {
+LL | | with_signature(a, b, |x, y| {
+LL | |
+LL | | //
+... |
+LL | | })
+LL | | }
+ | |_^
+ |
+ = note: defining type: no_region::<T>
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:27:26
+ |
+LL | with_signature(a, b, |x, y| {
+ | __________________________^
+LL | |
+LL | | //
+LL | | // See `correct_region`, which explains the point of this
+... |
+LL | | require(&x, &y)
+LL | | })
+ | |_____^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn no_region<'a, T: 'a>(a: Cell<&'a ()>, b: T) {
+ | ++++
+
+note: external requirements
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:43:26
+ |
+LL | with_signature(a, b, |x, y| {
+ | ^^^^^^
+ |
+ = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 3
+ = note: where T: '_#2r
+
+note: no external requirements
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:39:1
+ |
+LL | / fn correct_region<'a, T>(a: Cell<&'a ()>, b: T)
+LL | | where
+LL | | T: 'a,
+LL | | {
+... |
+LL | | })
+LL | | }
+ | |_^
+ |
+ = note: defining type: correct_region::<'_#1r, T>
+
+note: external requirements
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:64:26
+ |
+LL | with_signature(a, b, |x, y| {
+ | ^^^^^^
+ |
+ = note: defining type: wrong_region::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+ = note: number of external vids: 4
+ = note: where T: '_#2r
+
+note: no external requirements
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:60:1
+ |
+LL | / fn wrong_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
+LL | | where
+LL | | T: 'b,
+LL | | {
+... |
+LL | | })
+LL | | }
+ | |_^
+ |
+ = note: defining type: wrong_region::<'_#1r, T>
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:64:26
+ |
+LL | with_signature(a, b, |x, y| {
+ | __________________________^
+LL | |
+LL | | // See `correct_region`
+LL | | require(&x, &y)
+LL | | })
+ | |_____^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: 'b + 'a,
+ | ++++
+
+note: external requirements
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:77:26
+ |
+LL | with_signature(a, b, |x, y| {
+ | ^^^^^^
+ |
+ = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+ (),
+ ]
+ = note: number of external vids: 4
+ = note: where T: '_#3r
+
+note: no external requirements
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:72:1
+ |
+LL | / fn outlives_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
+LL | | where
+LL | | T: 'b,
+LL | | 'b: 'a,
+... |
+LL | | })
+LL | | }
+ | |_^
+ |
+ = note: defining type: outlives_region::<'_#1r, '_#2r, T>
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
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 000000000..98239f416
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/ty-param-fn-body.rs
@@ -0,0 +1,27 @@
+// Test that we assume that universal types like `T` outlive the
+// function body.
+
+#![allow(warnings)]
+
+use std::cell::Cell;
+
+// No errors here, because `'a` is local to the body.
+fn region_within_body<T>(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)
+ //~^ ERROR the parameter type `T` may not live long enough
+}
+
+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 000000000..5fb69255d
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr
@@ -0,0 +1,14 @@
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-fn-body.rs:17:5
+ |
+LL | outlives(cell, t)
+ | ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn region_static<'a, T: 'a>(cell: Cell<&'a usize>, t: T) {
+ | ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
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 000000000..4393a3b41
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/ty-param-fn.rs
@@ -0,0 +1,36 @@
+#![allow(warnings)]
+
+use std::fmt::Debug;
+
+fn no_region<'a, T>(x: Box<T>) -> Box<Debug + 'a>
+where
+ T: Debug,
+{
+ x
+ //~^ ERROR the parameter type `T` may not live long enough
+}
+
+fn correct_region<'a, T>(x: Box<T>) -> Box<Debug + 'a>
+where
+ T: 'a + Debug,
+{
+ x
+}
+
+fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
+where
+ T: 'b + Debug,
+{
+ x
+ //~^ ERROR the parameter type `T` may not live long enough
+}
+
+fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
+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 000000000..825b26d2f
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/ty-param-fn.stderr
@@ -0,0 +1,25 @@
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-fn.rs:9:5
+ |
+LL | x
+ | ^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: Debug + 'a,
+ | ++++
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-fn.rs:24:5
+ |
+LL | x
+ | ^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: 'b + Debug + 'a,
+ | ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/nll/ty-outlives/ty-param-implied-bounds.rs b/src/test/ui/nll/ty-outlives/ty-param-implied-bounds.rs
new file mode 100644
index 000000000..9042844e8
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/ty-param-implied-bounds.rs
@@ -0,0 +1,28 @@
+// compile-flags:-Zverbose
+// check-pass
+
+// Test that we assume that universal types like `T` outlive the
+// function body.
+
+use std::cell::Cell;
+
+fn twice<F, T>(value: T, mut f: F)
+where
+ F: FnMut(Cell<&T>),
+{
+ f(Cell::new(&value));
+ f(Cell::new(&value));
+}
+
+fn generic<T>(value: T) {
+ // No error here:
+ twice(value, |r| invoke(r));
+}
+
+fn invoke<'a, T>(x: Cell<&'a T>)
+where
+ T: 'a,
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/wf-unreachable.rs b/src/test/ui/nll/ty-outlives/wf-unreachable.rs
new file mode 100644
index 000000000..c6f4c4afa
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/wf-unreachable.rs
@@ -0,0 +1,52 @@
+// Test that we check that user type annotations are well-formed, even in dead
+// code.
+
+fn uninit<'a>() {
+ return;
+ let x: &'static &'a (); //~ ERROR lifetime may not live long enough
+}
+
+fn var_type<'a>() {
+ return;
+ let x: &'static &'a () = &&(); //~ ERROR lifetime may not live long enough
+}
+
+fn uninit_infer<'a>() {
+ let x: &'static &'a _; //~ ERROR lifetime may not live long enough
+ x = && ();
+}
+
+fn infer<'a>() {
+ return;
+ let x: &'static &'a _ = &&(); //~ ERROR lifetime may not live long enough
+}
+
+fn uninit_no_var<'a>() {
+ return;
+ let _: &'static &'a (); //~ ERROR lifetime may not live long enough
+}
+
+fn no_var<'a>() {
+ return;
+ let _: &'static &'a () = &&(); //~ ERROR lifetime may not live long enough
+}
+
+fn infer_no_var<'a>() {
+ return;
+ let _: &'static &'a _ = &&(); //~ ERROR lifetime may not live long enough
+}
+
+trait X<'a, 'b> {}
+
+struct C<'a, 'b, T: X<'a, 'b>>(T, &'a (), &'b ());
+
+impl X<'_, '_> for i32 {}
+impl<'a> X<'a, 'a> for () {}
+
+// This type annotation is not well-formed because we substitute `()` for `_`.
+fn required_substs<'a>() {
+ return;
+ let _: C<'static, 'a, _> = C((), &(), &()); //~ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/wf-unreachable.stderr b/src/test/ui/nll/ty-outlives/wf-unreachable.stderr
new file mode 100644
index 000000000..a62157f44
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/wf-unreachable.stderr
@@ -0,0 +1,73 @@
+error: lifetime may not live long enough
+ --> $DIR/wf-unreachable.rs:6:12
+ |
+LL | fn uninit<'a>() {
+ | -- lifetime `'a` defined here
+LL | return;
+LL | let x: &'static &'a ();
+ | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/wf-unreachable.rs:11:12
+ |
+LL | fn var_type<'a>() {
+ | -- lifetime `'a` defined here
+LL | return;
+LL | let x: &'static &'a () = &&();
+ | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/wf-unreachable.rs:15:12
+ |
+LL | fn uninit_infer<'a>() {
+ | -- lifetime `'a` defined here
+LL | let x: &'static &'a _;
+ | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/wf-unreachable.rs:21:12
+ |
+LL | fn infer<'a>() {
+ | -- lifetime `'a` defined here
+LL | return;
+LL | let x: &'static &'a _ = &&();
+ | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/wf-unreachable.rs:26:12
+ |
+LL | fn uninit_no_var<'a>() {
+ | -- lifetime `'a` defined here
+LL | return;
+LL | let _: &'static &'a ();
+ | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/wf-unreachable.rs:31:12
+ |
+LL | fn no_var<'a>() {
+ | -- lifetime `'a` defined here
+LL | return;
+LL | let _: &'static &'a () = &&();
+ | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/wf-unreachable.rs:36:12
+ |
+LL | fn infer_no_var<'a>() {
+ | -- lifetime `'a` defined here
+LL | return;
+LL | let _: &'static &'a _ = &&();
+ | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/wf-unreachable.rs:49:12
+ |
+LL | fn required_substs<'a>() {
+ | -- lifetime `'a` defined here
+LL | return;
+LL | let _: C<'static, 'a, _> = C((), &(), &());
+ | ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: aborting due to 8 previous errors
+