Please note that holding this viewpoint will not separate discontinuous borrowing from its source of reborrowing.
Discontinuous borrowing, like ordinary borrowing, can as a value place in a complex structure, but the difference is that it cannot be dereferenced when it cannot be proven effective.
The way to prove the effectiveness of a discontinuous lifetime is to require it to be a subtype of a regular lifetime.
Or, use a specific keyword?
When it cannot be proven, it can only be moved (or converted to raw pointer?) and other value operations, and dereference is prohibited.
The key to the problem is that discontinuous lifetime borrowing is logically completed at once, which is one operation, not multiple repeat operations.
let mut a = 1;
let mut b = 2;
let mut rs = [#[discontinuity] &mut a, #[discontinuity] &mut b];
a = 3;
b = 4;
// do some array operations
rs.swap(0, 1);
a = 5;
b = 6;
*rs[0] = 7;
*rs[1] = 8;
If we want to understand it through automatically reborrow, how can we explain its opaque array operations?
let mut a = 1;
let mut b = 2;
let mut rs /* [&#[discontinuity] '1 mut i32; 2] */ = [#[discontinuity] &mut a, #[discontinuity] &mut b];
a = 3;
b = 4;
// do some array operations
rs.swap(0, 1);
// do something. if need, '1 same valid in this
a = 5;
b = 6;
*rs[0] = 7; // '1
*rs[1] = 8; // '1
There is no irrationality in it.
Yes, I know, but just like this array, how can I borrow it again in this situation?
A normal lifetime borrowing is a continuous area on the Control flow graph. It is effective from creation to last use.
In the case of discontinuous lifetime borrowing, there can be multiple disconnected regions on the Control flow graph. It is not necessary to include a valid region when creating.
That is to say, this may seem a bit anti causal, for example, the following code can also be compiled:
let mut x = 1;
let y = &mut x;
let z = #[discontinuity] &mut x; // &#[discontinuity] '1 mut i32
*y = 2;
*z = 3; // '1 <- We just borrowed this paragraph
You haven't defined what it means to be "effective" though.
So a discontinuous lifetime may not be a "subtype" (can't find the correct term, but definitely shouldn't be "type") of a regular lifetime. Why? When does that happen?
What do you mean by "completed"?
Manually you can just do:
let mut a = 1;
let mut b = 2;
let mut rs = [&mut a, &mut b];
*rs[0] = 3;
*rs[1] = 4;
// do some array operations
rs.swap(0, 1);
*rs[1] = 5;
*rs[0] = 6;
*rs[0] = 7;
*rs[1] = 8;
Of course in this case it would be difficult for compiler to understand that it need to swap the path to a and b, and it would be easier to use some other criteria to allow access to those variables. You didn't explain those criteria though.
What I mean is, this line has borrowed everything it needs from now on.
If we have a simple control flow:
--------------------------------------
^
a --------------------->
Ordinary borrowing involves borrowing a continuous length.
--------------------------------------
^ ^-- 's --^
a----- --->
^&'s mut a
And discontinuous borrowing is different:
--------------------------------------------------------------
^ ^--- 'd ---^ ^&'s a --^ ^---- 'd ----^
a----------- --- ---- --->
^#[..]&'d mut a ^&'s a
<#[discontinuity] 's, 'a>
subtype where 's: 'a The meaning is that for any 'a effective control flow node, 's is always effective.
Due to the fact that ordinary lifetime are always valid as generic parameters when called, it can be inferred that discontinuous lifetime are valid in the current function call (this seems to be no different from the Variance between ordinary lifetime).
Is there anything wrong with the statement of subtypes?
I have heard of it before: &'a T is covariant in 'a, That's why I call it a subtype......