I think that &'a &'a T or any chain of reference using two time the same (non static) lifetime is always a bug. (EDIT: I’m looking at the lifetime of the references, not references to type generic over a liftetime). I think that it’s never what the programmer intended to write. For example:
And using any of those two can give extremely confusing error messages:
let mut x = "test";
foo(&mut x);
// or
let _ = Bar{x: &mut x};
assert_eq!(x, "test");
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
--> src/main.rs:12:9
|
11 | foo(&mut x);
| ------ mutable borrow occurs here
12 | assert_eq!(x, "test");
| ^^^^^^^^^^^^^^^^^^^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
Instead, I think that the compiler should say something like
help: it is possible that you want to use two different lifetimes
5 | fn foo<'a>(_: &'a mut &'a str) {
| ^^ ^^
help: you may try to introduce a new lifetime
5 | fn foo<'a1, 'a2>(_: &'a1 mut &'a2 str) {
| ^^^ ^^^ ^^^ ^^^
help: You can learn more about variance and lifetimes (todo: put a link)
Given that it’s a feature request for rustc, I wasn’t sure if I had to post here or on the user forum.
There are usecases for references to references of the same lifetime. For example in a custom reimplementation of the core::fmt infrastructure I have a type like
since all references and inner references of this type are expected to be temporaries of the same statement. Changing it to use two lifetimes like this:
does appear to pass all my tests, but that's more annoying for users having to write Arguments<'_, '_> everywhere, and I don't think it provides any additional value.
It’s not exactly the same. I don’t see the value of &'a &'a, but I can see the value of &'a S<'a>. I think a rustc warning for the former would be useful, but for the later a clippy lint is more than enough (can even be disabled by default).
In addition to &'a &'a, we should probably warn against &'a [&'a T].
This is not always a problem. &'a S<'a> has its uses, for example rustc has uses &'tcx TyS<'tcx> a lot. &'a &'a is pretty useless, but hardly a bug. The main problem is when the S in &'a S<'a> is invariant with respect to its lifetime parameter.
By the way I just saw this PR which might improve the error messages in cases like these.
These two are very different wrt variance. &mut T is invariant in T while &T is covariant T. Which is very significant. So yes, &'a mut [S<'a>] is usually a bug, but take out the mut, and it's usually benign.
Given that &'a &'a T is "morally equivalent" to &'a T (at least for T: Sized, a lint suggesting eliminating the extra indirection makes sense for at least clippy. This only holds for a literal &&T, though, of course, and when you are actually not using impls on &&T that aren't also on &T. You could even extend said lint for &'a &'b T to suggest collapsing to the shorter of the two lifetimes, so long as the longer lifetime parameter is not used elsewhere.
I'm not aware enough of how &'a mut &'a T can/'t be used, but I'm generally in favor of (accurate) lints that point out when you're making something harder on yourself for no benefit.
(And side note: yes &'a [&'a T] is fine, and any lint of this style probably wants a special case for 'static.)