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.
This commit is contained in:
commit
ebda7662db
24 changed files with 884 additions and 133 deletions
36
src/test/compile-fail/E0657.rs
Normal file
36
src/test/compile-fail/E0657.rs
Normal file
|
|
@ -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() {}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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() {}
|
||||
24
src/test/compile-fail/impl-trait/type_parameters_captured.rs
Normal file
24
src/test/compile-fail/impl-trait/type_parameters_captured.rs
Normal file
|
|
@ -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() {}
|
||||
97
src/test/run-pass/impl-trait/lifetimes.rs
Normal file
97
src/test/run-pass/impl-trait/lifetimes.rs
Normal file
|
|
@ -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() {}
|
||||
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue