Commit 9ef6e2199c introduced a check to
ensure that Clippy doesn't consider a lifetime present in an explicit
self type as being the default for an elided output lifetime. For
example, elision did not work in the case like:
```rust
fn func(self: &Rc<Self>, &str) -> &str { … }
```
Since Rust 1.81.0, the lifetime in the self type is now considered
the default for elision. Elision should then be suggested when
appropriate.
678 lines
17 KiB
Rust
678 lines
17 KiB
Rust
//@aux-build:proc_macros.rs
|
|
|
|
#![warn(clippy::needless_lifetimes)]
|
|
#![allow(
|
|
unused,
|
|
clippy::boxed_local,
|
|
clippy::extra_unused_type_parameters,
|
|
clippy::needless_pass_by_value,
|
|
clippy::redundant_allocation,
|
|
clippy::unnecessary_wraps,
|
|
dyn_drop,
|
|
clippy::get_first
|
|
)]
|
|
|
|
extern crate proc_macros;
|
|
use proc_macros::inline_macros;
|
|
|
|
fn distinct_lifetimes(_x: &u8, _y: &u8, _z: u8) {}
|
|
|
|
fn distinct_and_static(_x: &u8, _y: &u8, _z: &'static u8) {}
|
|
|
|
// No error; same lifetime on two params.
|
|
fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) {}
|
|
|
|
// No error; static involved.
|
|
fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) {}
|
|
|
|
fn mut_and_static_input(_x: &mut u8, _y: &'static str) {}
|
|
|
|
fn in_and_out(x: &u8, _y: u8) -> &u8 {
|
|
x
|
|
}
|
|
|
|
// No error; multiple input refs.
|
|
fn multiple_in_and_out_1<'a>(x: &'a u8, _y: &'a u8) -> &'a u8 {
|
|
x
|
|
}
|
|
|
|
// Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid:
|
|
// fn multiple_in_and_out_2a<'a>(x: &'a u8, _y: &u8) -> &'a u8
|
|
// ^^^
|
|
fn multiple_in_and_out_2a<'a>(x: &'a u8, _y: &u8) -> &'a u8 {
|
|
x
|
|
}
|
|
|
|
// Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid:
|
|
// fn multiple_in_and_out_2b<'b>(_x: &u8, y: &'b u8) -> &'b u8
|
|
// ^^^
|
|
fn multiple_in_and_out_2b<'b>(_x: &u8, y: &'b u8) -> &'b u8 {
|
|
y
|
|
}
|
|
|
|
// No error; multiple input refs
|
|
async fn func<'a>(args: &[&'a str]) -> Option<&'a str> {
|
|
args.get(0).cloned()
|
|
}
|
|
|
|
// No error; static involved.
|
|
fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 {
|
|
x
|
|
}
|
|
|
|
// Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid:
|
|
// fn deep_reference_1a<'a>(x: &'a u8, _y: &u8) -> Result<&'a u8, ()>
|
|
// ^^^
|
|
fn deep_reference_1a<'a>(x: &'a u8, _y: &u8) -> Result<&'a u8, ()> {
|
|
Ok(x)
|
|
}
|
|
|
|
// Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid:
|
|
// fn deep_reference_1b<'b>(_x: &u8, y: &'b u8) -> Result<&'b u8, ()>
|
|
// ^^^
|
|
fn deep_reference_1b<'b>(_x: &u8, y: &'b u8) -> Result<&'b u8, ()> {
|
|
Ok(y)
|
|
}
|
|
|
|
// No error; two input refs.
|
|
fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 {
|
|
x.unwrap()
|
|
}
|
|
|
|
fn deep_reference_3(x: &u8, _y: u8) -> Result<&u8, ()> {
|
|
Ok(x)
|
|
}
|
|
|
|
// Where-clause, but without lifetimes.
|
|
fn where_clause_without_lt<T>(x: &u8, _y: u8) -> Result<&u8, ()>
|
|
where
|
|
T: Copy,
|
|
{
|
|
Ok(x)
|
|
}
|
|
|
|
type Ref<'r> = &'r u8;
|
|
|
|
// No error; same lifetime on two params.
|
|
fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) {}
|
|
|
|
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!()
|
|
}
|
|
|
|
fn fn_bound_2<F, I>(_m: Lt<'_, I>, _f: F) -> Lt<'_, I>
|
|
where
|
|
for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>,
|
|
{
|
|
unreachable!()
|
|
}
|
|
|
|
// No error; see below.
|
|
fn fn_bound_3<'a, F: FnOnce(&'a i32)>(x: &'a i32, f: F) {
|
|
f(x);
|
|
}
|
|
|
|
fn fn_bound_3_cannot_elide() {
|
|
let x = 42;
|
|
let p = &x;
|
|
let mut q = &x;
|
|
// This will fail if we elide lifetimes of `fn_bound_3`.
|
|
fn_bound_3(p, |y| q = y);
|
|
}
|
|
|
|
// No error; multiple input refs.
|
|
fn fn_bound_4<'a, F: FnOnce() -> &'a ()>(cond: bool, x: &'a (), f: F) -> &'a () {
|
|
if cond { x } else { f() }
|
|
}
|
|
|
|
struct X {
|
|
x: u8,
|
|
}
|
|
|
|
impl X {
|
|
fn self_and_out(&self) -> &u8 {
|
|
&self.x
|
|
}
|
|
|
|
// Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid:
|
|
// fn self_and_in_out_1<'s>(&'s self, _x: &u8) -> &'s u8
|
|
// ^^^
|
|
fn self_and_in_out_1<'s>(&'s self, _x: &u8) -> &'s u8 {
|
|
&self.x
|
|
}
|
|
|
|
// Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid:
|
|
// fn self_and_in_out_2<'t>(&self, x: &'t u8) -> &'t u8
|
|
// ^^^^^
|
|
fn self_and_in_out_2<'t>(&self, x: &'t u8) -> &'t u8 {
|
|
x
|
|
}
|
|
|
|
fn distinct_self_and_in(&self, _x: &u8) {}
|
|
|
|
// No error; same lifetimes on two params.
|
|
fn self_and_same_in<'s>(&'s self, _x: &'s u8) {}
|
|
}
|
|
|
|
struct Foo<'a>(&'a u8);
|
|
|
|
impl<'a> Foo<'a> {
|
|
// No error; lifetime `'a` not defined in method.
|
|
fn self_shared_lifetime(&self, _: &'a u8) {}
|
|
// No error; bounds exist.
|
|
fn self_bound_lifetime<'b: 'a>(&self, _: &'b u8) {}
|
|
}
|
|
|
|
fn already_elided<'a>(_: &u8, _: &'a u8) -> &'a u8 {
|
|
unimplemented!()
|
|
}
|
|
|
|
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!()
|
|
}
|
|
|
|
// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is
|
|
// valid:
|
|
// fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str
|
|
// ^^
|
|
fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str {
|
|
unimplemented!()
|
|
}
|
|
|
|
// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is
|
|
// valid:
|
|
// fn struct_with_lt4b<'b>(_foo: &Foo<'b>) -> &'b str
|
|
// ^^^^
|
|
fn struct_with_lt4b<'b>(_foo: &Foo<'b>) -> &'b str {
|
|
unimplemented!()
|
|
}
|
|
|
|
trait WithLifetime<'a> {}
|
|
|
|
type WithLifetimeAlias<'a> = dyn WithLifetime<'a>;
|
|
|
|
// Should not warn because it won't build without the lifetime.
|
|
fn trait_obj_elided<'a>(_arg: &'a dyn WithLifetime) -> &'a str {
|
|
unimplemented!()
|
|
}
|
|
|
|
// Should warn because there is no lifetime on `Drop`, so this would be
|
|
// unambiguous if we elided the lifetime.
|
|
fn trait_obj_elided2(_arg: &dyn Drop) -> &str {
|
|
unimplemented!()
|
|
}
|
|
|
|
type FooAlias<'a> = Foo<'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!()
|
|
}
|
|
|
|
// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is
|
|
// valid:
|
|
// fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str
|
|
// ^^
|
|
fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str {
|
|
unimplemented!()
|
|
}
|
|
|
|
// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is
|
|
// valid:
|
|
// fn alias_with_lt4b<'b>(_foo: &FooAlias<'b>) -> &'b str
|
|
// ^^^^^^^^^
|
|
fn alias_with_lt4b<'b>(_foo: &FooAlias<'b>) -> &'b str {
|
|
unimplemented!()
|
|
}
|
|
|
|
fn named_input_elided_output(_arg: &str) -> &str {
|
|
unimplemented!()
|
|
}
|
|
|
|
fn elided_input_named_output<'a>(_arg: &str) -> &'a str {
|
|
unimplemented!()
|
|
}
|
|
|
|
fn trait_bound_ok<T: WithLifetime<'static>>(_: &u8, _: T) {
|
|
unimplemented!()
|
|
}
|
|
fn trait_bound<'a, T: WithLifetime<'a>>(_: &'a u8, _: T) {
|
|
unimplemented!()
|
|
}
|
|
|
|
// Don't warn on these; see issue #292.
|
|
fn trait_bound_bug<'a, T: WithLifetime<'a>>() {
|
|
unimplemented!()
|
|
}
|
|
|
|
// See issue #740.
|
|
struct Test {
|
|
vec: Vec<usize>,
|
|
}
|
|
|
|
impl Test {
|
|
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = usize> + 'a> {
|
|
unimplemented!()
|
|
}
|
|
}
|
|
|
|
trait LintContext<'a> {}
|
|
|
|
fn f<'a, T: LintContext<'a>>(_: &T) {}
|
|
|
|
fn test<'a>(x: &'a [u8]) -> u8 {
|
|
let y: &'a u8 = &x[5];
|
|
*y
|
|
}
|
|
|
|
// Issue #3284: give hint regarding lifetime in return type.
|
|
struct Cow<'a> {
|
|
x: &'a str,
|
|
}
|
|
fn out_return_type_lts(e: &str) -> Cow<'_> {
|
|
unimplemented!()
|
|
}
|
|
|
|
// Make sure we still warn on implementations
|
|
mod issue4291 {
|
|
trait BadTrait {
|
|
fn needless_lt(x: &u8) {}
|
|
}
|
|
|
|
impl BadTrait for () {
|
|
fn needless_lt(_x: &u8) {}
|
|
}
|
|
}
|
|
|
|
mod issue2944 {
|
|
trait Foo {}
|
|
struct Bar;
|
|
struct Baz<'a> {
|
|
bar: &'a Bar,
|
|
}
|
|
|
|
impl Foo for Baz<'_> {}
|
|
impl Bar {
|
|
fn baz(&self) -> impl Foo + '_ {
|
|
Baz { bar: self }
|
|
}
|
|
}
|
|
}
|
|
|
|
mod nested_elision_sites {
|
|
// issue #issue2944
|
|
|
|
// closure trait bounds subject to nested elision
|
|
// don't lint because they refer to outer lifetimes
|
|
fn trait_fn<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
|
|
move || i
|
|
}
|
|
fn trait_fn_mut<'a>(i: &'a i32) -> impl FnMut() -> &'a i32 {
|
|
move || i
|
|
}
|
|
fn trait_fn_once<'a>(i: &'a i32) -> impl FnOnce() -> &'a i32 {
|
|
move || i
|
|
}
|
|
|
|
// don't lint
|
|
fn impl_trait_in_input_position<'a>(f: impl Fn() -> &'a i32) -> &'a i32 {
|
|
f()
|
|
}
|
|
fn impl_trait_in_output_position<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
|
|
move || i
|
|
}
|
|
// lint
|
|
fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
|
|
f(i)
|
|
}
|
|
fn impl_trait_elidable_nested_anonymous_lifetimes(i: &i32, f: impl Fn(&i32) -> &i32) -> &i32 {
|
|
f(i)
|
|
}
|
|
|
|
// don't lint
|
|
fn generics_not_elidable<'a, T: Fn() -> &'a i32>(f: T) -> &'a i32 {
|
|
f()
|
|
}
|
|
// lint
|
|
fn generics_elidable<T: Fn(&i32) -> &i32>(i: &i32, f: T) -> &i32 {
|
|
f(i)
|
|
}
|
|
|
|
// don't lint
|
|
fn where_clause_not_elidable<'a, T>(f: T) -> &'a i32
|
|
where
|
|
T: Fn() -> &'a i32,
|
|
{
|
|
f()
|
|
}
|
|
// lint
|
|
fn where_clause_elidable<T>(i: &i32, f: T) -> &i32
|
|
where
|
|
T: Fn(&i32) -> &i32,
|
|
{
|
|
f(i)
|
|
}
|
|
|
|
// don't lint
|
|
fn pointer_fn_in_input_position<'a>(f: fn(&'a i32) -> &'a i32, i: &'a i32) -> &'a i32 {
|
|
f(i)
|
|
}
|
|
fn pointer_fn_in_output_position<'a>(_: &'a i32) -> fn(&'a i32) -> &'a i32 {
|
|
|i| i
|
|
}
|
|
// lint
|
|
fn pointer_fn_elidable(i: &i32, f: fn(&i32) -> &i32) -> &i32 {
|
|
f(i)
|
|
}
|
|
|
|
// don't lint
|
|
fn nested_fn_pointer_1<'a>(_: &'a i32) -> fn(fn(&'a i32) -> &'a i32) -> i32 {
|
|
|f| 42
|
|
}
|
|
fn nested_fn_pointer_2<'a>(_: &'a i32) -> impl Fn(fn(&'a i32)) {
|
|
|f| ()
|
|
}
|
|
|
|
// lint
|
|
fn nested_fn_pointer_3(_: &i32) -> fn(fn(&i32) -> &i32) -> i32 {
|
|
|f| 42
|
|
}
|
|
fn nested_fn_pointer_4(_: &i32) -> impl Fn(fn(&i32)) {
|
|
|f| ()
|
|
}
|
|
}
|
|
|
|
mod issue6159 {
|
|
use std::ops::Deref;
|
|
pub fn apply_deref<'a, T, F, R>(x: &'a T, f: F) -> R
|
|
where
|
|
T: Deref,
|
|
F: FnOnce(&'a T::Target) -> R,
|
|
{
|
|
f(x.deref())
|
|
}
|
|
}
|
|
|
|
mod issue7296 {
|
|
use std::rc::Rc;
|
|
use std::sync::Arc;
|
|
|
|
struct Foo;
|
|
impl Foo {
|
|
fn implicit(&self) -> &() {
|
|
&()
|
|
}
|
|
fn implicit_mut(&mut self) -> &() {
|
|
&()
|
|
}
|
|
#[clippy::msrv = "1.81"]
|
|
fn explicit(self: &Arc<Self>) -> &() {
|
|
&()
|
|
}
|
|
#[clippy::msrv = "1.81"]
|
|
fn explicit_mut(self: &mut Rc<Self>) -> &() {
|
|
&()
|
|
}
|
|
#[clippy::msrv = "1.80"]
|
|
fn explicit_older<'a>(self: &'a Arc<Self>) -> &'a () {
|
|
&()
|
|
}
|
|
#[clippy::msrv = "1.80"]
|
|
fn explicit_mut_older<'a>(self: &'a mut Rc<Self>) -> &'a () {
|
|
&()
|
|
}
|
|
|
|
fn lifetime_elsewhere(self: Box<Self>, here: &()) -> &() {
|
|
&()
|
|
}
|
|
}
|
|
|
|
trait Bar {
|
|
fn implicit(&self) -> &();
|
|
fn implicit_provided(&self) -> &() {
|
|
&()
|
|
}
|
|
|
|
#[clippy::msrv = "1.81"]
|
|
fn explicit(self: &Arc<Self>) -> &();
|
|
#[clippy::msrv = "1.81"]
|
|
fn explicit_provided(self: &Arc<Self>) -> &() {
|
|
&()
|
|
}
|
|
#[clippy::msrv = "1.80"]
|
|
fn explicit_older<'a>(self: &'a Arc<Self>) -> &'a ();
|
|
#[clippy::msrv = "1.80"]
|
|
fn explicit_provided_older<'a>(self: &'a Arc<Self>) -> &'a () {
|
|
&()
|
|
}
|
|
|
|
fn lifetime_elsewhere(self: Box<Self>, here: &()) -> &();
|
|
fn lifetime_elsewhere_provided(self: Box<Self>, here: &()) -> &() {
|
|
&()
|
|
}
|
|
}
|
|
}
|
|
|
|
mod pr_9743_false_negative_fix {
|
|
#![allow(unused)]
|
|
|
|
fn foo(x: &u8, y: &'_ u8) {}
|
|
|
|
fn bar(x: &u8, y: &'_ u8, z: &'_ u8) {}
|
|
}
|
|
|
|
mod pr_9743_output_lifetime_checks {
|
|
#![allow(unused)]
|
|
|
|
// lint: only one input
|
|
fn one_input(x: &u8) -> &u8 {
|
|
unimplemented!()
|
|
}
|
|
|
|
// lint: multiple inputs, output would not be elided
|
|
fn multiple_inputs_output_not_elided<'b>(x: &u8, y: &'b u8, z: &'b u8) -> &'b u8 {
|
|
unimplemented!()
|
|
}
|
|
|
|
// don't lint: multiple inputs, output would be elided (which would create an ambiguity)
|
|
fn multiple_inputs_output_would_be_elided<'a, 'b>(x: &'a u8, y: &'b u8, z: &'b u8) -> &'a u8 {
|
|
unimplemented!()
|
|
}
|
|
}
|
|
|
|
#[inline_macros]
|
|
mod in_macro {
|
|
use proc_macros::external;
|
|
|
|
// lint local macro expands to function with needless lifetimes
|
|
inline! {
|
|
fn one_input(x: &u8) -> &u8 {
|
|
unimplemented!()
|
|
}
|
|
}
|
|
|
|
// no lint on external macro
|
|
external! {
|
|
fn needless_lifetime<'a>(x: &'a u8) -> &'a u8 {
|
|
unimplemented!()
|
|
}
|
|
}
|
|
|
|
inline! {
|
|
fn f<$'a>(arg: &$'a str) -> &$'a str {
|
|
arg
|
|
}
|
|
}
|
|
}
|
|
|
|
mod issue5787 {
|
|
use std::sync::MutexGuard;
|
|
|
|
struct Foo;
|
|
|
|
impl Foo {
|
|
// doesn't get linted without async
|
|
pub async fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> {
|
|
guard
|
|
}
|
|
}
|
|
|
|
async fn foo<'a>(_x: &i32, y: &'a str) -> &'a str {
|
|
y
|
|
}
|
|
}
|
|
|
|
// https://github.com/rust-lang/rust-clippy/pull/13286#issuecomment-2374245772
|
|
mod rayon {
|
|
trait ParallelIterator {
|
|
type Item;
|
|
}
|
|
|
|
struct Copied<I: ParallelIterator> {
|
|
base: I,
|
|
}
|
|
|
|
impl<'a, T, I> ParallelIterator for Copied<I>
|
|
where
|
|
I: ParallelIterator<Item = &'a T>,
|
|
T: 'a + Copy + Send + Sync,
|
|
{
|
|
type Item = T;
|
|
}
|
|
}
|
|
|
|
mod issue13749 {
|
|
pub struct Generic<T>(T);
|
|
// Non elidable lifetime
|
|
#[expect(clippy::extra_unused_lifetimes)]
|
|
impl<'a, T> Generic<T> where T: 'a {}
|
|
}
|
|
|
|
mod issue13749bis {
|
|
pub struct Generic<T>(T);
|
|
// Non elidable lifetime
|
|
#[expect(clippy::extra_unused_lifetimes)]
|
|
impl<'a, T: 'a> Generic<T> {}
|
|
}
|
|
|
|
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)),
|
|
}
|
|
}
|
|
}
|
|
|
|
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)),
|
|
}
|
|
}
|
|
}
|
|
|
|
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),
|
|
}
|
|
}
|
|
}
|
|
|
|
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 main() {}
|