-
Notifications
You must be signed in to change notification settings - Fork 14.1k
Description
Code
pub struct Abc {
a: i32,
}
impl Abc {
pub fn iter(&self) -> std::slice::Iter<i32> {
std::slice::from_ref(&self.a).iter()
}
}Current output
warning: hiding a lifetime that's elided elsewhere is confusing
--> src/lib.rs:6:17
|
6 | pub fn iter(&self) -> std::slice::Iter<i32> {
| ^^^^^ ^^^^^^^^^^^^^^^^^^^^^ the same lifetime is hidden here
| |
| the lifetime is elided here
|
= help: the same lifetime is referred to in inconsistent ways, making the signature confusing
= note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
help: use `'_` for type paths
|
6 | pub fn iter(&self) -> std::slice::Iter<'_, i32> {
| +++Desired output
warning: hidden lifetime parameters are deprecated
--> src/lib.rs:6:17
|
6 | pub fn iter(&self) -> std::slice::Iter<i32> {
| ^^^^^ -----------------^--- expected a lifetime parameter here
| |
| a lifetime is elided here
|
= help: types with hidden lifetimes look like owned types and are confusing when used with elided lifetimes
= note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
help: use `'_` for types to show they are borrowed
|
6 | pub fn iter(&self) -> std::slice::Iter<'_, i32> {
| +++Rationale and extra context
According to the 1.89 release post, the whole rationale for mismatched_lifetime_syntaxes is that we want to deprecate hidden lifetimes entirely (the lint elided_lifetimes_in_paths) but it's too much to do all at once. So there is a clear goal in mind. Rustc has tried to get closer by recognising a difference between hidden and elided lifetimes.
Unfortunately this implementation strategy has leaked into the error message. I think that the error message for mismatched_lifetime_syntaxes is really hard to get your head around. Even if this is a less bothersome/frequent/annoying and more focused/useful lint than elided_lifetimes_in_paths, it is about 20x harder to understand why the compiler is warning you.
One lint is a subset of the other. We can very directly compare them. This is elided_lifetimes_in_paths at 1.91.1, minus the 'where lint is declared' part:
error: hidden lifetime parameters in types are deprecated
--> thing.rs:2:37
|
2 | fn yeah(x: &u32) -> std::slice::Iter<u32> {
| ----------------^---- expected lifetime parameter
|
help: indicate the anonymous lifetime
|
2 | fn yeah(x: &u32) -> std::slice::Iter<'_, u32> {
| +++
My reaction to each diagnostic is:
elided_lifetimes_in_paths: "hidden lifetime parameters in types are deprecated"- Instant comprehension. No new concepts. Very simple remedy: stop hiding your lifetimes in types. It's a simple rule you can follow to write clearer code.
mismatched_lifetime_syntaxes: "hiding a lifetime that's elided elsewhere is confusing"- I think... what is the difference between hiding and eliding? Which one is which? I would have guessed that these are synonyms.
- Which the error message has had to prepare for... "this one's hiding, this one's eliding"
- And then the kicker: Hint: the same lifetime is referred to in inconsistent ways...
- To which I think... Uh, no, the lifetime is not referred to at all! There is not a single piece of lifetime syntax here.
- So:
- Long time to understand what I did wrong
- Hint makes comprehension harder by being wrong
- Error message is phrased with no clear directive for avoiding this error in future
- Objectively, we have actually observed users feel bad when they see it. I think it's because "this is confusing" is not neutral enough, it's a criticism of the code.
mismatched_lifetime_syntaxesshould treat &T and ContainsLifetime as equivalent #145312
I think we can do better. I think we should just say "hidden lifetimes are deprecated", because it is the attitude you want users to adopt anyway. The way we managed to detect a confusing use of them is not important to the programmer. I think this should be an implementation detail. You can use the other lifetimes it mismatches with to pluck out some context, and that remains useful. I also think the lint can use this to show users why we have decided to deprecate, better than elided_lifetimes_in_paths ever could. I think this phrasing is also less liable to sound judgmental, because "x is deprecated" is not an accusation.
Other background
RalfJung explains hidden vs elided lifetimes in #145312 (comment). It's a fine shade between these two concepts, but sure, it exists.
Other cases
Rust Version
rustc 1.91.1 (ed61e7d7e 2025-11-07)
binary: rustc
commit-hash: ed61e7d7e242494fb7057f2657300d9e77bb4fcb
commit-date: 2025-11-07
host: x86_64-unknown-linux-gnu
release: 1.91.1
LLVM version: 21.1.2Anything else?
No response