-
Notifications
You must be signed in to change notification settings - Fork 1.6k
False positive for needless_lifetimes
#740
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Yeah, I have a similar example (Adapter from rust-bio). I'm unsure how to fix it however. |
Rustful also has one: src/router/tree_router.rs:80:5: 110:6 warning: explicit lifetimes given in parameter types where they could be elided, #[warn(needless_lifetimes)] on by default
src/router/tree_router.rs: 80 fn merge_router<'a, I: Iterator<Item = &'a [u8]> + Clone>(&mut self, state: InsertState<'a, I>, router: TreeRouter<T>) {
src/router/tree_router.rs: 81 self.item.insert_router(state.clone(), router.item);
src/router/tree_router.rs: 82
src/router/tree_router.rs: 83 for (key, router) in router.static_routes {
src/router/tree_router.rs: 84 let next = match self.static_routes.entry(key.clone()) {
src/router/tree_router.rs: 85 Occupied(entry) => entry.into_mut(),
...
src/router/tree_router.rs:80:5: 110:6 help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes |
Do I understand this right and the problem is that |
Fix some Clippy warnings There are 5 warnings left: - one `needless_lifetimes` which is a false positive (reported there: https://github.com/Manishearth/rust-clippy/issues/740#issuecomment-205826823); - 3 `type_complexity` warnings that I did not fix because they seem legit; - one `wrong_self_convention` which seems semi-legit too, although it’s a little surprising to have an `is_empty` function require a `&mut self`. Here they are, FYI: ```rust src/router/tree_router.rs:80:5: 110:6 warning: explicit lifetimes given in parameter types where they could be elided, #[warn(needless_lifetimes)] on by default src/router/tree_router.rs: 80 fn merge_router<'a, I: Iterator<Item = &'a [u8]> + Clone>(&mut self, state: InsertState<'a, I>, router: TreeRouter<T>) { src/router/tree_router.rs: 81 self.item.insert_router(state.clone(), router.item); src/router/tree_router.rs: 82 src/router/tree_router.rs: 83 for (key, router) in router.static_routes { src/router/tree_router.rs: 84 let next = match self.static_routes.entry(key.clone()) { src/router/tree_router.rs: 85 Occupied(entry) => entry.into_mut(), ... src/router/tree_router.rs:80:5: 110:6 help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes src/router/mod.rs:357:21: 357:71 warning: very complex type used. Consider factoring parts into `type` definitions, #[warn(type_complexity)] on by default src/router/mod.rs:357 type Segments = RouteIter<Split<'a, u8, &'static fn(&u8) -> bool>>; ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/router/mod.rs:357:21: 357:71 help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#type_complexity src/router/mod.rs:365:21: 365:71 warning: very complex type used. Consider factoring parts into `type` definitions, #[warn(type_complexity)] on by default src/router/mod.rs:365 type Segments = RouteIter<Split<'a, u8, &'static fn(&u8) -> bool>>; ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/router/mod.rs:365:21: 365:71 help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#type_complexity src/router/mod.rs:393:21: 393:170 warning: very complex type used. Consider factoring parts into `type` definitions, #[warn(type_complexity)] on by default src/router/mod.rs:393 type Segments = FlatMap<<&'a I as IntoIterator>::IntoIter, <<T as Deref>::Target as Route<'a>>::Segments, fn(&'a T) -> <<T as Deref>::Target as Route<'a>>::Segments>; ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/router/mod.rs:393:21: 393:170 help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#type_complexity src/router/mod.rs:449:21: 449:34 warning: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name, #[warn(wrong_self_convention)] on by default src/router/mod.rs:449 pub fn is_empty(&mut self) -> bool { ^~~~~~~~~~~~~ src/router/mod.rs:449:21: 449:34 help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention ```
Another case:
|
A tricky false positive from the standard library: HashMap::keys pub fn keys<'a>(&'a self) -> Keys<'a, K, V> {
fn first<A, B>((a, _): (A, B)) -> A { a }
let first: fn((&'a K, &'a V)) -> &'a K = first; // coerce to fn ptr
Keys { inner: self.iter().map(first) }
} The lifetime could be elided in the function signature, but the implementation requires it to be named. |
That’s a tricky one, we don’t even look for the implementation right now AFAIK. @dtolnay thanks for the report! |
That lifetime isn't necessary in the implementation AFAICT |
How do I get rid of it? playpen link It seems necessary because the inner function needs explicit lifetimes and cannot declare them itself. |
@Manishearth If you remove the lifetimes in that example: fn foo<'a>(a: &'a u8) -> &'a u8 {
fn bar<A, B>((a, _): (A, B)) -> A { a }
let baz: fn((&'a u8, &'a u8)) -> &'a u8 = bar;
baz((a, a))
} you get: <anon>:3:32: 3:35 error: missing lifetime specifier [E0106]
<anon>:3 let baz: fn((&u8, &u8)) -> &u8 = bar;
^~~
<anon>:3:32: 3:35 help: see the detailed explanation for E0106
<anon>:3:32: 3:35 help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 elided lifetimes it is borrowed from |
Huh, I see. Interesting. We could just walk the body for uses of the lifetime and bail |
Here is another example we're running into in our codebase (similar to OP). pub fn components<'a>(&'a self) -> Box<Iterator<Item=&'a str> + 'a> {
Box::new(self.path.components().map(|c| c.to_str().unwrap()))
} The lifetime can't be elided because the box inner needs to have the same lifetime as self which is not inferable from the callsite. |
This also pops up with pub fn pixels<'a>(&'a self) -> impl Iterator<Item=((u32, u32), &'a T)> { // ... In that case it's not just a wrong default, AFAIK one can never omit the lifetime in |
Another one: fn f<'a, T: LintContext<'a>>(cx: &T) {} |
This is producing many false positives in Rocket's codebase. I want to suggest making this lint |
So to recap: We have three classes of false positives:
|
This is another type of false positive: #![allow(dead_code)]
#[derive(Debug)]
struct Foo<'a> {
x: &'a f64,
}
impl<'a> Foo<'a> {
// Clippy treats this as fine.
fn with_x(self, x: &'a f64) -> Foo<'a> {
Foo {
x: x
}
}
}
#[derive(Debug)]
struct Bar<'a> {
x: &'a f64,
}
impl<'a> Bar<'a> {
// Clippy gives a needless_lifetimes warning.
fn with_x<'b>(self, x: &'b f64) -> Bar<'b> {
Bar {
x: x
}
}
}
fn main() {
// This doesn't work for Foo:
// let x1 = 1.;
// let struct1 = {
// let x2 = 2.;
// let struct2 = Foo {
// x: &x2,
// };
// struct2.with_x(&x1)
// };
// println!("{:?}", struct1);
// The exact same thing works for Bar:
let x1 = 1.;
let struct1 = {
let x2 = 2.;
let struct2 = Bar {
x: &x2,
};
struct2.with_x(&x1)
};
println!("{:?}", struct1);
} The The flexible behavior of |
Here's a trivial example that should trigger it. Removing the lifetime annotations causes the code not to compile (
cannot infer an appropriate lifetime ...
), but clippy gives aneedless_lifetimes
warning.The text was updated successfully, but these errors were encountered: