The code
trait Ts<'a>: 'a {}
impl<'a, T: 'a> Ts<'a> for T {}
fn a<'b, 'a: 'b>(_n: &'a mut i32, _m: &'b mut i32) {
static mut E: i32 = 9;
let _c: &'a mut (dyn Ts<'b> + 'a) = unsafe { &mut *std::ptr::addr_of_mut!(E) };
}
got the error:
|
4 | fn a<'b, 'a: 'b>(_n: &'a mut i32, _m: &'b mut i32) {
| -- -- lifetime `'a` defined here
| |
| lifetime `'b` defined here
5 | static mut E: i32 = 9;
6 | let _c: &'a mut (dyn Ts<'b> + 'a) = unsafe { &mut *std::ptr::addr_of_mut!(E) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
Why 'b:'a is required?
Ts<'b> has a bound Self: 'b
, so dyn Ts<'b>
has some lifetime which at least is not shorter than 'b. Hence 'a: 'b
Then (dyn Ts<'b> + 'a) as a whole keeps alive while 'a is in scope.
So, to my understanding, no 'b: 'a should be required to keep the code sound
You have to think about it this way:
When you write &'a Something
or &'a mut Something
, you are borrowing Something
for a specific amount of time ('a
), therefore Something
must outlive 'a
.
But if T: 'a, then there is no need of other bounds to make &'a T sound.
dyn Ts<'b> + 'a means a trait object with lifetime 'a, it is 'a already.
Yes, but the lifetime in the trait Ts<'b>
creates an implied bound. Maybe reading this could help you: Trait bound interactions - Learning Rust
The implied bound it created is 'a : 'b
, and it adds nothing more because this bound has already specified
No. The implied bound it creates is 'b : 'a
.
Ok, let's check the example and mine
pub trait LifetimeTrait<'a, 'b>: 'a {}
fn fp<'a, 'b, 'c>(t: Box<dyn LifetimeTrait<'a, 'b> + 'c>) {
// This compiles which indicates an implied `'c: 'a` bound
let c: &'c [()] = &[];
[...]
}
// ====================
trait Ts<'a>: 'a {}
fn a<'b, 'a: 'b>(_n: &'a mut i32, _m: &'b mut i32) {
let _c: &'a mut (dyn Ts<'b> + 'a) = ...
}
An implied 'c: 'a
in dyn LifetimeTrait<'a, '_> + 'c
An implied 'a: 'b
in dyn Ts<'b> + 'a
There is no difference
Maybe this example helps:
pub trait LifetimeTrait<'a>: 'a {}
struct MyStruct;
impl<'a> LifetimeTrait<'a> for MyStruct {}
fn fp<'b, 'a: 'b>(t: &'a mut Box<dyn LifetimeTrait<'b>>) {
}
fn main() {
let my_struct = MyStruct {};
let mut my_box: Box<dyn LifetimeTrait> = Box::new(my_struct);
fp(&mut my_box);
}
It will fail to compile because of the implied bound.
zylthinking1:
Why 'b:'a is required?
The only bounds (explicit or implicit) on the inputs to the function are 'a: 'b
, but the appearance of 'b
underneath a &'a mut
requires 'b: 'a
.
It's just a noisier version of this:
fn a<'b, 'a: 'b>(_n: &'a mut i32, _m: &'b mut i32) {
let _c: &'a &'b [(); 0] = &&[];
}
Trying to construct a type with lifetime requirements not expressed in the function signature.
Even with &'r (dyn Ts<'b> + 'static
), 'b: 'r
is required. The outlives relation is syntactic.
That's the crux of this topic as far as I can tell.
Can this be changed? I don't think so, certainly not without some breakage and peril.
Breakage: &'r (dyn Ts<'b> + 'a)
in a signature introduces an implied 'b: 'r
bound that would have to go away, breaking some code directly, and the presumed fix (an explicit bound) would change some functions to no longer have higher-ranked implementations of the Fn
traits, potentially breaking more code, ...
Peril: Unsafe code may be relying on the 'b: 'r
requirement (and/or implied bounds) in order to be sound themselves
It's correct that dyn Ts<'b> + 'a
in the signature wouldn't change anything since you already have the explicit 'a: 'b
bound.
It's not the dyn Ts<'b> + 'a
that's problematic, it's the &'a mut dyn Ts<'b>
.
1 Like
system
Closed
December 23, 2024, 5:39pm
10
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.