#![warn(clippy::needless_lifetimes, clippy::elidable_lifetime_names)] type Ref<'r> = &'r u8; // No error; same lifetime on two params. fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) {} //~v ERROR: could be elided: 'a, 'b fn lifetime_param_2(_x: Ref<'_>, _y: &u8) {} // No error; bounded lifetime. fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) {} // No error; bounded lifetime. fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8) where 'b: 'a, { } struct Lt<'a, I: 'static> { x: &'a I, } // No error; fn bound references `'a`. fn fn_bound<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> where F: Fn(Lt<'a, I>) -> Lt<'a, I>, { unreachable!() } //~v ERROR: could be elided: 'a fn fn_bound_2(_m: Lt<'_, I>, _f: F) -> Lt<'_, I> where for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>, { unreachable!() } struct Foo<'a>(&'a u8); //~v ERROR: could be elided: 'a fn struct_with_lt(_foo: Foo<'_>) -> &str { unimplemented!() } // No warning; two input lifetimes (named on the reference, anonymous on `Foo`). fn struct_with_lt2<'a>(_foo: &'a Foo) -> &'a str { unimplemented!() } // No warning; two input lifetimes (anonymous on the reference, named on `Foo`). fn struct_with_lt3<'a>(_foo: &Foo<'a>) -> &'a str { unimplemented!() } //~v ERROR: could be elided: 'b fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str { unimplemented!() } type FooAlias<'a> = Foo<'a>; //~v ERROR: could be elided: 'a fn alias_with_lt(_foo: FooAlias<'_>) -> &str { unimplemented!() } // No warning; two input lifetimes (named on the reference, anonymous on `FooAlias`). fn alias_with_lt2<'a>(_foo: &'a FooAlias) -> &'a str { unimplemented!() } // No warning; two input lifetimes (anonymous on the reference, named on `FooAlias`). fn alias_with_lt3<'a>(_foo: &FooAlias<'a>) -> &'a str { unimplemented!() } //~v ERROR: could be elided: 'b fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str { unimplemented!() } // Issue #3284: give hint regarding lifetime in return type. struct Cow<'a> { x: &'a str, } //~v ERROR: could be elided: 'a fn out_return_type_lts(e: &str) -> Cow<'_> { unimplemented!() } mod issue2944 { trait Foo {} struct Bar; struct Baz<'a> { bar: &'a Bar, } //~v ERROR: could be elided: 'a impl Foo for Baz<'_> {} impl Bar { //~v ERROR: could be elided: 'a fn baz(&self) -> impl Foo + '_ { Baz { bar: self } } } } mod issue13923 { struct Py<'py> { data: &'py str, } enum Content<'t, 'py> { Py(Py<'py>), T1(&'t str), T2(&'t str), } enum ContentString<'t> { T1(&'t str), T2(&'t str), } impl<'t, 'py> ContentString<'t> { // `'py` cannot be elided fn map_content1(self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, 'py> { match self { Self::T1(content) => Content::T1(f(content)), Self::T2(content) => Content::T2(f(content)), } } } //~v ERROR: could be elided: 'py impl<'t> ContentString<'t> { // `'py` can be elided because of `&self` fn map_content2(&self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, '_> { match self { Self::T1(content) => Content::T1(f(content)), Self::T2(content) => Content::T2(f(content)), } } } //~v ERROR: could be elided: 'py impl<'t> ContentString<'t> { // `'py` can be elided because of `&'_ self` fn map_content3(&'_ self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, '_> { match self { Self::T1(content) => Content::T1(f(content)), Self::T2(content) => Content::T2(f(content)), } } } impl<'t, 'py> ContentString<'t> { // `'py` should not be elided as the default lifetime, even if working, could be named as `'t` fn map_content4(self, f: impl FnOnce(&'t str) -> &'t str, o: &'t str) -> Content<'t, 'py> { match self { Self::T1(content) => Content::T1(f(content)), Self::T2(_) => Content::T2(o), } } } //~v ERROR: could be elided: 'py impl<'t> ContentString<'t> { // `'py` can be elided because of `&Self` fn map_content5( self: std::pin::Pin<&Self>, f: impl FnOnce(&'t str) -> &'t str, o: &'t str, ) -> Content<'t, '_> { match *self { Self::T1(content) => Content::T1(f(content)), Self::T2(_) => Content::T2(o), } } } struct Cx<'a, 'b> { a: &'a u32, b: &'b u32, } // `'c` cannot be elided because we have several input lifetimes fn one_explicit<'b>(x: Cx<'_, 'b>) -> &'b u32 { x.b } } fn issue15666_original() { struct UnitVariantAccess<'a, 'b, 's>(&'a &'b &'s ()); trait Trait<'de> {} //~v elidable_lifetime_names impl<'de> Trait<'de> for UnitVariantAccess<'_, 'de, '_> {} // ^^ ^^ ^^ ^^ } #[allow(clippy::upper_case_acronyms)] fn issue15666() { struct S1<'a>(&'a ()); struct S2<'a, 'b>(&'a &'b ()); struct S3<'a, 'b, 'c>(&'a &'b &'c ()); trait T {} trait TA<'a> {} trait TB<'b> {} trait TC<'c> {} trait TAB<'a, 'b> {} trait TAC<'a, 'c> {} trait TBC<'b, 'c> {} trait TABC<'a, 'b, 'c> {} // 1 lifetime impl<'a> TA<'a> for S1<'a> {} //~v elidable_lifetime_names impl T for S1<'_> {} // ^^ // 2 lifetimes impl<'a, 'b> TAB<'a, 'b> for S2<'a, 'b> {} //~v elidable_lifetime_names impl<'a> TA<'a> for S2<'a, '_> {} // ^^ //~v elidable_lifetime_names impl<'b> TB<'b> for S2<'_, 'b> {} // ^^ //~v elidable_lifetime_names impl T for S2<'_, '_> {} // ^^ ^^ // 3 lifetimes impl<'a, 'b, 'c> TABC<'a, 'b, 'c> for S3<'a, 'b, 'c> {} //~v elidable_lifetime_names impl<'a, 'b> TAB<'a, 'b> for S3<'a, 'b, '_> {} // ^^ //~v elidable_lifetime_names impl<'a, 'c> TAC<'a, 'c> for S3<'a, '_, 'c> {} // ^^ //~v elidable_lifetime_names impl<'a> TA<'a> for S3<'a, '_, '_> {} // ^^ ^^ //~v elidable_lifetime_names impl<'b, 'c> TBC<'b, 'c> for S3<'_, 'b, 'c> {} // ^^ //~v elidable_lifetime_names impl<'b> TB<'b> for S3<'_, 'b, '_> {} // ^^ ^^ //~v elidable_lifetime_names impl<'c> TC<'c> for S3<'_, '_, 'c> {} // ^^ ^^ //~v elidable_lifetime_names impl T for S3<'_, '_, '_> {} // ^^ ^^ ^^ }