Stream: t-compiler/wg-nll

Topic: why-is-this-ok-with-nll


Jake Goulding (Sep 12 2018 at 16:20, on Zulip):

Why does this compile with NLL?

use std::collections::HashSet;

fn main() {
    let mut h = HashSet::new();
    let a = 1;
    let b = 2;
    h.insert((&a, &b));
}
nikomatsakis (Sep 12 2018 at 16:21, on Zulip):

why wouldn't it?

nikomatsakis (Sep 12 2018 at 16:22, on Zulip):

I guess you are imagining: there is a drop on HashSet, and it has access to those (invalid) references?

Jake Goulding (Sep 12 2018 at 16:22, on Zulip):

yep

nikomatsakis (Sep 12 2018 at 16:22, on Zulip):

this is because HashSet declares that it doesn't touch the K, V pairs during drop

Jake Goulding (Sep 12 2018 at 16:22, on Zulip):

does hashset have the... yeah

nikomatsakis (Sep 12 2018 at 16:22, on Zulip):

via its #[may_dangle] attribute

Jake Goulding (Sep 12 2018 at 16:23, on Zulip):

I guess the flip question is then... why doesn't it work without NLL?

Jake Goulding (Sep 12 2018 at 16:23, on Zulip):

Is NLL aware of may_dangle?

nikomatsakis (Sep 12 2018 at 16:24, on Zulip):

NLL is aware of #[may_dangle], yes

nikomatsakis (Sep 12 2018 at 16:24, on Zulip):

as is the AST borrowck

nikomatsakis (Sep 12 2018 at 16:25, on Zulip):

the reason that it didn't work with the old borrowck is that there is a fundamental rule that the type of each variable must be live until the end of the block

nikomatsakis (Sep 12 2018 at 16:25, on Zulip):

or, sort of, right up until it is dropped (but not necessarily during the call to drop itself)

nikomatsakis (Sep 12 2018 at 16:25, on Zulip):

(that is where may-dangle comes in)

Jake Goulding (Sep 12 2018 at 16:26, on Zulip):

in AST borrowck, when would may_dangle have an effect?

nikomatsakis (Sep 12 2018 at 16:26, on Zulip):

so, in this case, the h type has to be live until it is dropped, but that outlives a

nikomatsakis (Sep 12 2018 at 16:26, on Zulip):

you can observe it if you build up cycles

nikomatsakis (Sep 12 2018 at 16:26, on Zulip):

it's rather awkward to do, but it happens

nikomatsakis (Sep 12 2018 at 16:26, on Zulip):

arenas are a case of this:

nikomatsakis (Sep 12 2018 at 16:26, on Zulip):

when you allocate from an arena, you get something that lives with its lifetime, and you can build up cycles amongst those data structures

Jake Goulding (Sep 12 2018 at 16:36, on Zulip):

Do you think that with the spread of NLL, may_dangle may gain more prominence? Since it will be more obvious that code in this general shape can work for Vec but not for MyCustomContainer?

I guess if it's built on top of one of the stdlib containers you can benefit...

Jake Goulding (Sep 12 2018 at 16:36, on Zulip):

thus pushing to stabilize it in some fashion

nikomatsakis (Sep 12 2018 at 16:37, on Zulip):

hmm

nikomatsakis (Sep 12 2018 at 16:38, on Zulip):

I hadn't thought about that

nikomatsakis (Sep 12 2018 at 16:38, on Zulip):

perhaps

nikomatsakis (Sep 12 2018 at 16:38, on Zulip):

I would like to get our story straight

nikomatsakis (Sep 12 2018 at 16:38, on Zulip):

there are also some details of how it integrates with NLL that need a bit of work

Jake Goulding (Sep 12 2018 at 16:40, on Zulip):

Is "values in a scope are dropped in the opposite order they are created" no longer strictly true? Is h dropped before a? Or is there actually some dangly going on?

nikomatsakis (Sep 12 2018 at 16:41, on Zulip):

it is strictly true

nikomatsakis (Sep 12 2018 at 16:42, on Zulip):

but we only require data to be live where it is used now

nikomatsakis (Sep 12 2018 at 16:42, on Zulip):

and we know the drop of h doesn't use a

Jake Goulding (Sep 12 2018 at 16:43, on Zulip):

which is via the #[may_dangle]

nikomatsakis (Sep 12 2018 at 16:43, on Zulip):

yes

Jake Goulding (Sep 12 2018 at 16:44, on Zulip):

I can see why you might want to have a more general "I guarantee this function won't access this value" then, and why it would be very difficult to get that right

nikomatsakis (Sep 12 2018 at 16:45, on Zulip):

I think that @RalfJ's approach feels pretty right, but we've not tried to work it out too hard

nikomatsakis (Sep 12 2018 at 16:45, on Zulip):

basically being able to say that, in contrast to a regular function, this type need not be valid in this function

nikomatsakis (Sep 12 2018 at 16:45, on Zulip):

this will in turn have to propagate to helper functions and the like

nikomatsakis (Sep 12 2018 at 16:46, on Zulip):

there is basically an implicit outlives clause in all functions now that says

nikomatsakis (Sep 12 2018 at 16:46, on Zulip):

for each type parameter T, the value given for T must outlive the call to the fn itself

nikomatsakis (Sep 12 2018 at 16:46, on Zulip):

this would be sort of removing that... but it has trickle-down effects

nikomatsakis (Sep 12 2018 at 16:47, on Zulip):

e.g., right now, drop has the signature &mut self -- but normally we require that &'a mut Self is valid if Self: 'a

nikomatsakis (Sep 12 2018 at 16:47, on Zulip):

and here we are saying that the self is valid (so 'a is live) but some of the data in Self is not...?

nikomatsakis (Sep 12 2018 at 16:47, on Zulip):

not sure how to deal with that

Keith Yeung (Sep 12 2018 at 16:47, on Zulip):

huh, so that means temporaries created just for the purpose of being an argument to a function call already outlives the call itself nowadays?

nikomatsakis (Sep 12 2018 at 16:50, on Zulip):

yes

nikomatsakis (Sep 12 2018 at 16:50, on Zulip):

(of course?)

Jake Goulding (Sep 12 2018 at 16:50, on Zulip):

https://stackoverflow.com/questions/47662253/why-is-it-legal-to-borrow-a-temporary

Keith Yeung (Sep 12 2018 at 16:51, on Zulip):

because lexically it looks as if it only lives during the function call, not outlive it

Jake Goulding (Sep 12 2018 at 16:51, on Zulip):

conceptually, it outlives the call by like one line

Jake Goulding (Sep 12 2018 at 16:52, on Zulip):
foo(&String::new());
{
    let __a = String::new();
    foo(&__a);
}
Last update: Nov 21 2019 at 13:05UTC