-
Notifications
You must be signed in to change notification settings - Fork 73
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
possible refinement to avoid tracking subset relations #107
Comments
I realized an interesting example last night -- it may be that this analysis is itself not as precise as it could be. The following example (playground) is rejected by today's NLL and I think would be rejected by the formulation I described above, but is accepted by today's polonius. In order to accept it, we would have to make #![allow(warnings)]
fn main() {
let mut a: Vec<&u32> = vec![];
let mut b: Vec<&u32> = vec![];
let mut c: Vec<&u32> = vec![];
let mut p: &mut Vec<&u32> = &mut c;
let mut i = 22;
if foo() {
p = &mut a;
p.push(&i);
drop(a);
i += 1; // `i` is no longer borrowed, ok
drop(b);
} else {
p = &mut b;
p.push(&i);
drop(b);
i += 1; // `i` is no longer borrowed, ok
drop(a);
}
}
fn foo() -> bool {
true
} |
We've done some more digging into this and it appears that the idea, as described, is somewhat flawed. First of all, I want to link to this playground which contains the original motivational example (or a variation of it). This was buried in the Zulip thread above. In any case, we ran into a problem with the promoted bounds example. Digging into the problem in this Zulip thread, we found that the problem is kind of "foundational" in the way that this issue is described. In particular, there are cases where we do have to propagate "subset" relations forward, because they establish important relationships between otherwise independent types and not just "instantaneous effects". Here is a variant of the "promoted bounds" example (playground) that I found identified the problem even more crisply: fn shorten_lifetime<'a, 'b, 'min>(a: &'a i32, b: &'b i32) -> &'min i32 { ... }
fn main() {
let promoted_fn_item_ref: fn(_, _) -> _ = shorten_lifetime;
let a = &5;
let ptr = {
let l = 3;
let b = &l; //~ ERROR does not live long enough
let c = promoted_fn_item_ref(a, b);
c
};
drop(ptr);
} So what is happening here? The interesting part is this first line: let promoted_fn_item_ref: fn(_, _) -> _ = shorten_lifetime; What is going to happen here is that we are going to assign What's important is that the In the equality model, those subset relationships would be "instantaneously" enforced on the first line, but that's not good enough, they have to persist until the function is called. On the first line, You could construct a similar example, I imagine, using a data structure. The idea would be that you have some kind of |
Current status: As it stands, this idea is flawed. We're leaving the issue open because there might be a kernel of an idea here, but it'll take some refinement to find it.
As discussed on Zulip, @aatxe and I realized that we can refine the polonius analysis to be more precise and (potentially) faster.
The key idea is that we do not need to propagate the subset relation forward through time (i.e., across the control-flow graph). The important thing is for us to distinguish instantaneous flow of data from persistent flow. In our current setup, persistent flow corresponds to invariance -- basically cycles in the subset relation. (I think this is an interesting observation and points to there being some kind of refinement possible to be more precise, but that's neither here nor there for the moment).
As an example, the following assignment represents an instantaneous flow of data:
This would create a
'p: 'q
subset relation (read as'p
flows into'q
). But the point is that this occurs once. If'p
later comes to refer to new loans somehow, that doesn't affect'q
.In contrast, with a mutable reference, you do want the effects to propagate:
The rough idea then is to say that when you have equality of two regions (in this case, of
'v
and'p
) polonius should propagate that forward, but not a mere subset relation. Another way to think of it is thatv
andp
ought to have been given the same region in the first place, in order for the type check to succeed:Anyway, we ought to be able to prototype this like so:
Remove the logic that propagates
subset
relations between points and so forth.We first detect compute the transition subset relation at each location -- but only considering the facts introduced at that location. (Today's
subset_base
.)equality(R1, R2)
relation -- two regions are equal if, at any point P, they are subsets of one another:contains
relation based on equality:I .. think that's it?
The text was updated successfully, but these errors were encountered: