-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Add RFC: formalise reborrows #2364
Conversation
Related to this there is what could be considered a bug in this example: trait Counter { ... }
impl<'a, C: Counter + ?Sized> Counter for &'a mut C { ... }
fn do_thing<C: Counter>(mut c: C) { ... }
let mut c: &mut Counter = ...;
do_thing(c); // does not reborrow
do_thing::<&mut Counter>(c); // identical except does reborrow |
The unexpressible type here can be expressed via generic associated types (tracking issue) Edit: even that is less than ideal. What we reallly want here is to also constrain the output type to be the same as the input (up to some lifetime). |
Since this is a coercion, you might want to take a look at |
text/0000-formalise-reborrows.md
Outdated
|
||
When a parameter `x` is passed into a function `f` (e.g. `f(x)`), | ||
|
||
- if `x` supports `Copy` [and `x` is later reused], then a copy of `x` will |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it is necessary to qualify this with x is later reused
. A copy is just a move that does not mark the value as uninitialized.
text/0000-formalise-reborrows.md
Outdated
|
||
- if `x` supports `Copy` [and `x` is later reused], then a copy of `x` will | ||
be passed into `f` | ||
- if `x` supports `Reborrow` [and `x` is later reused], then a reborrow of `x` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar here, though in this case it's an honest question from me; does it matter whether x
is later used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would presume the optimiser can replace a reborrow with a move — maybe that should be mentioned explicitly.
It's more complicated than that unfortunately, because we don't know how many lifetimes are needed (e.g. the type |
I think exploring
Also, there are already several distinct I suppose associated type makes sense if you could really only reborrow in one way though:
|
A reborrow is supposed to yield the same type except that all lifetimes are fresh, subsets of the corresponding lifetimes, and (when mutable) block the parent lifetimes until expiry. Thus there should only be one way to reborrow; anything else is a coercion I guess. This is not merely a life-time shrinkage; I really don't think Personally I think the next move should be to try implementing this; despite the unexpressible lifetime I think it should be possible. I was going to try, but am busy with other things now, and don't have much experience with the compiler internals. P.S. do we even have formal notation to express that one |
I think your
You'll notice
and
It's frequently important the mutable lifetime cannot be shrunk inside say rent_to_own, which corresponds to Is this invariance restriction workable? If no then I suppose this explains your desire for a new As an aside, we presumably cannot generically
|
There are no automatic reborrows in Rust when passing a value that aren't coercions.
That's not the case - For the
For mutable reborrows: that's not in the library implementations of You can definitely shrink the |
FWIW, as a @rust-lang/compiler member I'm opposed to adding anything that behaves like a coercion but introduces new machinery instead of generalizing the existing coercion machinery. Not only is the proposed "inexpressible type" pretty much impossible to implement in the current compiler, it's also unsound (see the rules about unconstrained lifetimes in return types). Also, the existing |
@rfcbot fcp postpone So I strongly agree with the motivation of this RFC, but I don't feel the timing is right. It seems to me that the changes here intersect three distinct ongoing tasks, all of which are higher priority. I'd rather wait to see those tasks play out before layering changes on top. The tasks are:
(Generally speaking, I think I agree with @eddyb that something along the lines of In any case, for the reasons above, I move to postpone. |
Team member @nikomatsakis has proposed to postpone this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
The final comment period is now complete. |
Postponed per #2364 (comment) and completed FCP. Thanks @dhardy! |
I have a internal post a few weeks ago, proposed a solution of this without lifetime shrinking or coercing. However it needs to adjust our mental model from "reborrowing" to "reviving". The idea is, when call a function like
I assume the above should always indistinguishable in case of |
@earthengine this doesn't solve the first example in the RFC:
|
@earthengine Note that types not invariant over lifetimes (so anything that only uses shared references) have subtyping (e.g. I still prefer a generalized form of opt-in "coerce a type by coercing its fields" (#2364 (comment)). |
I understand |
I know reborrow is no-op like And the proposal is to use |
@earthengine the point isn't to "copy" but to "borrow", however having to deal with |
The idea of let mut i = 42;
let mut v = Some(&mut i);
match v {
Some(v) => *v+=1,
None => {}
}
match v {
Some(v) => *v+=1,
None => {}
} if Because In general, Is this answered your question? |
The hard part in your proposal is making "revive" work with lifetime analysis. My proposal here is that you call Further, But I don't really know why you're trying to convince me. I only wrote an RFC... |
As something implied in my "Revive" proposal, something is also apply to this RFC. We should consider making closures implement This is similar to |
Summary: Formalise the re-borrowing logic used on
&T
and&mut T
.Motivation: Solve #1403: Some way to simulate
&mut
reborrows in user code.Rendered