diff options
| author | bors <bors@rust-lang.org> | 2017-11-21 10:00:18 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2017-11-21 10:00:18 +0000 |
| commit | ebda7662dbb79ab0a9feb79d367d0818c23ff1dc (patch) | |
| tree | 9419cba6023e30a6a130c9b0c59bdab0bd169b58 /src/test | |
| parent | bac7c53bc3842b494af098dbab8723fde9c97da2 (diff) | |
| parent | 450bbc5f94ab0c015268246bc91324020b7c37fd (diff) | |
Auto merge of #45701 - cramertj:impl-trait-this-time, r=eddyb
impl Trait Lifetime Handling
This PR implements the updated strategy for handling `impl Trait` lifetimes, as described in [RFC 1951](https://github.com/rust-lang/rfcs/blob/master/text/1951-expand-impl-trait.md) (cc #42183).
With this PR, the `impl Trait` desugaring works as follows:
```rust
fn foo<T, 'a, 'b, 'c>(...) -> impl Foo<'a, 'b> { ... }
// desugars to
exists type MyFoo<ParentT, 'parent_a, 'parent_b, 'parent_c, 'a, 'b>: Foo<'a, 'b>;
fn foo<T, 'a, 'b, 'c>(...) -> MyFoo<T, 'static, 'static, 'static, 'a, 'b> { ... }
```
All of the in-scope (parent) generics are listed as parent generics of the anonymous type, with parent regions being replaced by `'static`. Parent regions referenced in the `impl Trait` return type are duplicated into the anonymous type's generics and mapped appropriately.
One case came up that wasn't specified in the RFC: it's possible to write a return type that contains multiple regions, neither of which outlives the other. In that case, it's not clear what the required lifetime of the output type should be, so we generate an error.
There's one remaining FIXME in one of the tests: `-> impl Foo<'a, 'b> + 'c` should be able to outlive both `'a` and `'b`, but not `'c`. Currently, it can't outlive any of them. @nikomatsakis and I have discussed this, and there are some complex interactions here if we ever allow `impl<'a, 'b> SomeTrait for AnonType<'a, 'b> { ... }`, so the plan is to hold off on this until we've got a better idea of what the interactions are here.
cc #34511.
Fixes #44727.
Diffstat (limited to 'src/test')
| -rw-r--r-- | src/test/compile-fail/E0657.rs | 36 | ||||
| -rw-r--r-- | src/test/compile-fail/impl-trait/lifetimes.rs | 43 | ||||
| -rw-r--r-- | src/test/compile-fail/impl-trait/must_outlive_least_region_or_bound.rs | 39 | ||||
| -rw-r--r-- | src/test/compile-fail/impl-trait/needs_least_region_or_bound.rs | 23 | ||||
| -rw-r--r-- | src/test/compile-fail/impl-trait/type_parameters_captured.rs | 24 | ||||
| -rw-r--r-- | src/test/run-pass/impl-trait/lifetimes.rs | 97 | ||||
| -rw-r--r-- | src/test/ui/span/loan-extend.rs | 24 |
7 files changed, 219 insertions, 67 deletions
diff --git a/src/test/compile-fail/E0657.rs b/src/test/compile-fail/E0657.rs new file mode 100644 index 00000000000..b72a8f03089 --- /dev/null +++ b/src/test/compile-fail/E0657.rs @@ -0,0 +1,36 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![allow(warnings)] +#![feature(conservative_impl_trait)] + +trait Id<T> {} +trait Lt<'a> {} + +impl<'a> Lt<'a> for () {} +impl<T> Id<T> for T {} + +fn free_fn_capture_hrtb_in_impl_trait() + -> impl for<'a> Id<impl Lt<'a>> + //~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level [E0657] +{ + () +} + +struct Foo; +impl Foo { + fn impl_fn_capture_hrtb_in_impl_trait() + -> impl for<'a> Id<impl Lt<'a>> + //~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level + { + () + } +} + +fn main() {} diff --git a/src/test/compile-fail/impl-trait/lifetimes.rs b/src/test/compile-fail/impl-trait/lifetimes.rs deleted file mode 100644 index 9d9f6bf7297..00000000000 --- a/src/test/compile-fail/impl-trait/lifetimes.rs +++ /dev/null @@ -1,43 +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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(conservative_impl_trait)] - -// Helper creating a fake borrow, captured by the impl Trait. -fn borrow<'a, T>(_: &'a mut T) -> impl Copy { () } - -fn stack() -> impl Copy { - //~^ ERROR only named lifetimes are allowed in `impl Trait` - let x = 0; - &x -} - -fn late_bound(x: &i32) -> impl Copy { - //~^ ERROR only named lifetimes are allowed in `impl Trait` - x -} - -// FIXME(#34511) Should work but doesn't at the moment, -// region-checking needs an overhault to support this. -fn early_bound<'a>(x: &'a i32) -> impl Copy { - //~^ ERROR only named lifetimes are allowed in `impl Trait` - x -} - -fn ambiguous<'a, 'b>(x: &'a [u32], y: &'b [u32]) -> impl Iterator<Item=u32> { - //~^ ERROR only named lifetimes are allowed in `impl Trait` - if x.len() < y.len() { - x.iter().cloned() - } else { - y.iter().cloned() - } -} - -fn main() {} diff --git a/src/test/compile-fail/impl-trait/must_outlive_least_region_or_bound.rs b/src/test/compile-fail/impl-trait/must_outlive_least_region_or_bound.rs new file mode 100644 index 00000000000..837160bc2fc --- /dev/null +++ b/src/test/compile-fail/impl-trait/must_outlive_least_region_or_bound.rs @@ -0,0 +1,39 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(conservative_impl_trait)] + +use std::fmt::Debug; + +fn elided(x: &i32) -> impl Copy { x } +//~^ ERROR cannot infer an appropriate lifetime + +fn explicit<'a>(x: &'a i32) -> impl Copy { x } +//~^ ERROR cannot infer an appropriate lifetime + +trait LifetimeTrait<'a> {} +impl<'a> LifetimeTrait<'a> for &'a i32 {} + +fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } +//~^ ERROR cannot infer an appropriate lifetime + +// Tests that a closure type contianing 'b cannot be returned from a type where +// only 'a was expected. +fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) { + //~^ ERROR lifetime mismatch + move |_| println!("{}", y) +} + +fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static { + //~^ ERROR the parameter type `T` may not live long enough + x +} + +fn main() {} diff --git a/src/test/compile-fail/impl-trait/needs_least_region_or_bound.rs b/src/test/compile-fail/impl-trait/needs_least_region_or_bound.rs new file mode 100644 index 00000000000..2a06580fe60 --- /dev/null +++ b/src/test/compile-fail/impl-trait/needs_least_region_or_bound.rs @@ -0,0 +1,23 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(conservative_impl_trait)] + +use std::fmt::Debug; + +trait MultiRegionTrait<'a, 'b> {} +impl<'a, 'b> MultiRegionTrait<'a, 'b> for (&'a u32, &'b u32) {} + +fn no_least_region<'a, 'b>(x: &'a u32, y: &'b u32) -> impl MultiRegionTrait<'a, 'b> { +//~^ ERROR ambiguous lifetime bound + (x, y) +} + +fn main() {} diff --git a/src/test/compile-fail/impl-trait/type_parameters_captured.rs b/src/test/compile-fail/impl-trait/type_parameters_captured.rs new file mode 100644 index 00000000000..c6ff762b905 --- /dev/null +++ b/src/test/compile-fail/impl-trait/type_parameters_captured.rs @@ -0,0 +1,24 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(conservative_impl_trait)] + +use std::fmt::Debug; + +trait Any {} +impl<T> Any for T {} + +// Check that type parameters are captured and not considered 'static +fn foo<T>(x: T) -> impl Any + 'static { + //~^ ERROR the parameter type `T` may not live long enough + x +} + +fn main() {} diff --git a/src/test/run-pass/impl-trait/lifetimes.rs b/src/test/run-pass/impl-trait/lifetimes.rs new file mode 100644 index 00000000000..1e19e7f6a13 --- /dev/null +++ b/src/test/run-pass/impl-trait/lifetimes.rs @@ -0,0 +1,97 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(conservative_impl_trait)] +#![allow(warnings)] + +use std::fmt::Debug; + +fn any_lifetime<'a>() -> &'a u32 { &5 } + +fn static_lifetime() -> &'static u32 { &5 } + +fn any_lifetime_as_static_impl_trait() -> impl Debug { + any_lifetime() +} + +fn lifetimes_as_static_impl_trait() -> impl Debug { + static_lifetime() +} + +fn no_params_or_lifetimes_is_static() -> impl Debug + 'static { + lifetimes_as_static_impl_trait() +} + +fn static_input_type_is_static<T: Debug + 'static>(x: T) -> impl Debug + 'static { x } + +fn type_outlives_reference_lifetime<'a, T: Debug>(x: &'a T) -> impl Debug + 'a { x } + +trait SingleRegionTrait<'a> {} +impl<'a> SingleRegionTrait<'a> for u32 {} + +fn simple_type_hrtb<'b>() -> impl for<'a> SingleRegionTrait<'a> { 5 } +fn closure_hrtb() -> impl for<'a> Fn(&'a u32) { |_| () } + +fn mixed_lifetimes<'a>() -> impl for<'b: 'a> Fn(&'b u32) { |_| () } +fn mixed_as_static() -> impl Fn(&'static u32) { mixed_lifetimes() } + +trait MultiRegionTrait<'a, 'b>: Debug {} + +#[derive(Debug)] +struct MultiRegionStruct<'a, 'b>(&'a u32, &'b u32); +impl<'a, 'b> MultiRegionTrait<'a, 'b> for MultiRegionStruct<'a, 'b> {} + +#[derive(Debug)] +struct NoRegionStruct; +impl<'a, 'b> MultiRegionTrait<'a, 'b> for NoRegionStruct {} + +fn finds_least_region<'a: 'b, 'b>(x: &'a u32, y: &'b u32) -> impl MultiRegionTrait<'a, 'b> { + MultiRegionStruct(x, y) +} + +fn finds_explicit_bound<'a: 'b, 'b> + (x: &'a u32, y: &'b u32) -> impl MultiRegionTrait<'a, 'b> + 'b +{ + MultiRegionStruct(x, y) +} + +fn finds_explicit_bound_even_without_least_region<'a, 'b> + (x: &'a u32, y: &'b u32) -> impl MultiRegionTrait<'a, 'b> + 'b +{ + NoRegionStruct +} + +/* FIXME: `impl Trait<'a> + 'b` should live as long as 'b, even if 'b outlives 'a +fn outlives_bounds_even_with_contained_regions<'a, 'b> + (x: &'a u32, y: &'b u32) -> impl Debug + 'b +{ + finds_explicit_bound_even_without_least_region(x, y) +} +*/ + +fn unnamed_lifetimes_arent_contained_in_impl_trait_and_will_unify<'a, 'b> + (x: &'a u32, y: &'b u32) -> impl Debug +{ + fn deref<'lt>(x: &'lt u32) -> impl Debug { *x } + + if true { deref(x) } else { deref(y) } +} + +fn can_add_region_bound_to_static_type<'a, 'b>(_: &'a u32) -> impl Debug + 'a { 5 } + +struct MyVec(Vec<Vec<u8>>); + +impl<'unnecessary_lifetime> MyVec { + fn iter_doesnt_capture_unnecessary_lifetime<'s>(&'s self) -> impl Iterator<Item = &'s u8> { + self.0.iter().flat_map(|inner_vec| inner_vec.iter()) + } +} + +fn main() {} diff --git a/src/test/ui/span/loan-extend.rs b/src/test/ui/span/loan-extend.rs deleted file mode 100644 index a4b951daab4..00000000000 --- a/src/test/ui/span/loan-extend.rs +++ /dev/null @@ -1,24 +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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(conservative_impl_trait)] - -// Helper creating a fake borrow, captured by the impl Trait. -fn borrow<'a, T>(_: &'a mut T) -> impl Copy { () } - -fn main() { - let long; - let mut short = 0; - long = borrow(&mut short); - //~^ NOTE borrow occurs here -} -//~^ ERROR `short` does not live long enough -//~| NOTE `short` dropped here while still borrowed -//~| NOTE values in a scope are dropped in the opposite order they are created |
