-
Notifications
You must be signed in to change notification settings - Fork 12
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
free region support #12
Comments
How do we translate something like |
I think the best way to solve this is to I think the "abstract lifetime" is a better way of thinking about skolemized lifetimes than trying to shoehorn them into the CFG. |
Hmm, so I also find this appealing, and in the past I went down this road for a bit. I remember getting concerned that sometimes it would interact poorly, causing excessively long borrows. I am having a bit of trouble recovering the precise case I was concerned about. I know that it had something to do with the get-default pattern, which is roughly this:
Here, the key point is that we start borrow (in START) that is conditionally returned. If we call the lifetime of that borrow
The way the RFC describes it, this means that we trace (and include) all points reachable from SOME/0 that are also included in Maybe, to make this more concrete, we would say that regions are defined by So, if we did something like that, how does the outlives relation work? I think, within the CFG, you copy points over "as today", and the "skolemized end" points are not relevant to that bit. However, if the "source" (sub) region ( Does this make sense so far? Seem kind of like what you were thinking? |
OK, I did a quick sort of prototype for the approach I was describing on this branch https://github.com/nikomatsakis/nll/tree/issue-12-free-regions. I've not had much time to play around with it yet, and it's missing some bits, but the key idea is that:
I am not sure if this is correct, particularly the final propagation rule, but it gives us something to play with and think about more thoroughly. One thing I want to revisit in particular is this example that @arielb1 gave earlier (to make sure it behaves as I would like it to):
I think this will work out fine -- the borrow for |
I think "post-end skolemized variables" is a better name than "end points" - they aren't just points (if you "inlined" a function, they would turn into the subgraph of the CFG that contains the lifetime of the region after the function return) but can have arbitrary relationships between them.
That sounds sound. If control flow can never reach the exit, all free regions are guaranteed to be live, and therefore equal. |
Just a clarification question here, do you use "skolemized" as a synonym here for "free lifetimes", a.k.a. "the lifetimes quantified over in the function type"? (That does not at all match the way I would use "skolemized", so I am somewhat confused. ;) ) |
I'm using "skolemized" for what rustc calls "skolemized" ~~actually closer to "Herbrandized"~~actually that depends on your POV - to mean free lifetimes that are supposed to be "closed over" by a universal quantifier we're trying to prove, and therefore can't acquire any "incidental" constraints (as opposed to lifetimes that are supposed to be "closed over" by universal quantifiers we're assuming/existential quantifiers we're proving, which can and do acquire any set of consistent constraints). |
Heh. To be honest, I've been wondering myself why I'm using the term skolemized and not "free" all of a sudden. I guess I just think it's a fun word to say and not wholly inappropriate. =) Anyway, for the purpose of this discussion, I am referring to the named lifetime parameters that are in scope within a function. (It is, also, probably useful to distinguish the skolemized lifetimes that we create when solving a higher-ranked trait bound, as I imagine we'll wind up treating them somewhat differently internally, even if they seem conceptually quite similar (albeit with no known relation to the CFG).) |
I see. In Coq lingo, I would call the free/skolemized lifetimes just "lifetime variables (in the current context)" -- things that are set by the context and that we do not have control over -- while the lifetimes we still have to pick are "lifetime evars". Anyway, now I understand what you are talking about :) |
@arielb1 I agree that the "end regions" are not really points, I just found that the most convenient way to hack up the basic idea. I think it'd be clearer to treat them differently in the code (and description). |
There is preliminary support for "free regions" in master now but it's kind of broken. The rough idea is to extend the control-flow graph to include synthetic nodes that contain the "end" of the various free regions. But there are some flaws with the current implementation. This issue exists to take some notes.
If there are multiple free regions, we are not handling their relationships together correctly. We want to create sort of "pessimistic" edges. This is a bit trickier, I think, then I first considered. Here is an example:
Key here is that
'a
and'b
get merged (because they outlive one another).'c
and'd
do not -- so we want to ensure that eitherEnd(c)
orEnd(d)
could occur first. These graphs are in some sense not ideal, because they include infeasible paths (i.e.,d
might never end), but I think it's ok for our purposes, since we care about possible paths that do exist (we don't have any intersection analyses, right?).Also, we need to ensure that borrowing data of lifetime
'b
for lifetime'a
will result in an error (presuming no ordering between the two). I had imagined this working as a result of the inference edges that result. I think that will still work, but not the way that free regions are currently implemented (since they map to lifetime variables). In particular, we need to add "verification constraints" that force (e.g., in example above)'b
to not contain the end region nodes for anything but'a
(since'b: 'a
) and the control-flow graph.The text was updated successfully, but these errors were encountered: