Skip to content
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

refactor `used_mut_nodes` result #42384

Closed
nikomatsakis opened this Issue Jun 2, 2017 · 9 comments

Comments

Projects
None yet
3 participants
@nikomatsakis
Copy link
Contributor

nikomatsakis commented Jun 2, 2017

At present, when you run borrowck, it also has the side-effect of modifying the used_mut_nodes set in the tcx:

    /// Set of nodes which mark locals as mutable which end up getting used at
    /// some point. Local variable definitions not in this set can be warned
    /// about.
    pub used_mut_nodes: RefCell<NodeSet>,

This set is used later by the lint machinery: any mut declaration not in this set gets a warning.

This is not good, because that field is not tracking by the incremental system. The other problem is just that this very setup -- one big set -- is sort of anti-incremental, since we can't readily track which contributions to the set came from where.

I think we should refactor this so that the borrowck query, instead of yielding a unit result, as it does now, returns a NodeSet containing the list of used mut nodes within the body. Note that whether a mut is used is purely determinde by the function it is in, so we don't need to combine results from multiple borrowck results.

In other words, we would remove that field from the tcx and change the entry in src/librustc/ty/maps.rs for the borrowck from this:

    [] borrowck: BorrowCheck(DefId) -> (),

to something like this:

    [] borrowck: BorrowCheck(DefId) -> Rc<BorrowCheckResult>,

where BorrowCheckResult would be a new struct defined (presumably) in src/librustc/ty.rs, looking something like this:

struct BorrowCheckResult {
    /// contains the node-ids for variables within this function where the `mut`
    /// declaration was used in some way (e.g., by modifying the variable's value,
    /// or taking an `&mut` borrow of it).
    used_mut_nodes: NodeSet
}

We would then modify the borrow checker code (borrowck() in src/librustc_borrowck/borrowck/mod.rs) so that instead of modifying the tcx directly, it modifies a set defined per-fn, and constructs the struct when it is done.

Finally, we would have to modify the lint code that currently reads from this set (found in src/librustc_lint/unused.rs). This is a bit annoying, since late's don't seem to naturally want to carry state, and we don't have quite the helpers you would need to make it stateless.

One option -- adding state -- would be to add a field to the UnusedMut struct that tricks the innermost body (it's type might be Vec<Rc<BorrowCheckResult>>). Then we would want to modify the LateLintPass impl, which implements a "visitor-like" pattern, where you get callbacks as we descend the HIR. We would want to override check_body, so that each time we enter a fn body (etc), we can load up the borrowck results for that fn (we can keep them in a stack). Something like this:

fn check_body(&mut self, cx: &LateContext, body: &'tcx hir::Body) {
    // Get the def-id of the owner of this body, typically a function.
    let body_owner_def_id = cx.tcx().hir.body_owner_def_id(body.id());
    
    // Get the borrowck tables.
    self.borrowck_tables.push(cx.tcx().borrowck(body_owner_def_id));
}

fn check_body_post(&mut self, cx: &LateContext, body: &'tcx hir::Body) {
    self.borrowck_tables.pop();
}

then we can check whether a given mut binding is "used" by invoking self.borrowck_tables.last().unwrap().contains(...) (the vector ought to be non-empty, I think, though that could be wrong for cases like function parameters).

@cynicaldevil

This comment has been minimized.

Copy link
Contributor

cynicaldevil commented Jun 2, 2017

I'll take this up!

@nikomatsakis

This comment has been minimized.

Copy link
Contributor Author

nikomatsakis commented Jun 3, 2017

@cynicaldevil great! Please let me know how you're doing. I try to monitor GitHub notifications, but if you want a quick answer to a question, I find it works best if you ping me on IRC (if you have a persistent connection, especially) or else gitter. And of course there is also #rustc on IRC.

@nikomatsakis

This comment has been minimized.

Copy link
Contributor Author

nikomatsakis commented Jun 20, 2017

@cynicaldevil how goes it?

@cynicaldevil

This comment has been minimized.

Copy link
Contributor

cynicaldevil commented Jun 20, 2017

Still working on it, I have a few questions to ask via IRC later :)

@cynicaldevil

This comment has been minimized.

Copy link
Contributor

cynicaldevil commented Jun 24, 2017

@nikomatsakis I've changed the borrowck entry in define_maps to return Rc<BorrowCheckResult>.
Now, I'm refactoring out the used_mut_nodes field, which I've removed. For example, I've changed self.tcx().used_mut_nodes.borrow_mut().insert(local_id); to self.tcx().borrowck(_).get_mut().used_mut_nodes.insert(local_id);. Problem is, the borrowck call requires a DefId argument, and I can't figure out how to obtain one.

@nikomatsakis

This comment has been minimized.

Copy link
Contributor Author

nikomatsakis commented Jun 27, 2017

@cynicaldevil hmm, that doesn't sound quite right. I would expect borrowck to return an immutable result, for one thing. Maybe post a link to your WIP branch and I can take a look?

@cynicaldevil

This comment has been minimized.

Copy link
Contributor

cynicaldevil commented Jun 30, 2017

@nikomatsakis

This comment has been minimized.

Copy link
Contributor Author

nikomatsakis commented Jul 17, 2017

@cynicaldevil gah sorry, please do ping me on IRC or gitter in the future if I have overlooked a comment of yours! I left these notes, hope it is helpful.

@Mark-Simulacrum Mark-Simulacrum added C-bug C-cleanup and removed C-bug labels Jul 27, 2017

@cynicaldevil

This comment has been minimized.

Copy link
Contributor

cynicaldevil commented Aug 7, 2017

I've modified the commit acc. to comments: cynicaldevil@df15479, and I've started working on the lint code now.

alexcrichton added a commit to alexcrichton/rust that referenced this issue Oct 14, 2017

rustc: Remove `used_mut_nodes` from `TyCtxt`
This updates the borrowck query to return a result, and this result is then used
to incrementally check for unused mutable nodes given sets of all the used
mutable nodes.

Closes rust-lang#42384

alexcrichton added a commit to alexcrichton/rust that referenced this issue Oct 14, 2017

rustc: Remove `used_mut_nodes` from `TyCtxt`
This updates the borrowck query to return a result, and this result is then used
to incrementally check for unused mutable nodes given sets of all the used
mutable nodes.

Closes rust-lang#42384

bors added a commit that referenced this issue Oct 16, 2017

Auto merge of #45283 - alexcrichton:used-mut-nodes, r=arielb1
rustc: Remove `used_mut_nodes` from `TyCtxt`

This updates the borrowck query to return a result, and this result is then used
to incrementally check for unused mutable nodes given sets of all the used
mutable nodes.

Closes #42384

@bors bors closed this in #45283 Oct 16, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.