Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upAdd Borrow and Ownership structs and fields #5
Conversation
Nashenas88
reviewed
Jun 4, 2017
| } | ||
|
|
||
| #[derive(Debug, Clone, RustcDecodable, RustcEncodable)] | ||
| pub enum CauseData { |
This comment has been minimized.
This comment has been minimized.
Nashenas88
Jun 4, 2017
Author
Contributor
I'm not sure if exposing the causes for loans and moves is a good idea. Would this be too coupled to compiler internals? The idea behind exposing these is that people would be able to ask "why" a loan or move occurred.
This comment has been minimized.
This comment has been minimized.
nrc
Jun 6, 2017
Member
I would not, at least at first. I would start with a very simple system, then add stuff.
nrc
reviewed
Jun 6, 2017
| @@ -42,6 +42,7 @@ pub struct Analysis { | |||
| pub refs: Vec<Ref>, | |||
| pub macro_refs: Vec<MacroRef>, | |||
| pub relations: Vec<Relation>, | |||
| pub borrows: Vec<Borrows>, | |||
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Nashenas88
Jun 6, 2017
Author
Contributor
Each Borrows object represents all of the borrows in a single function/closure. The vec represents the collection of borrows for all functions/closures in a crate. I could have also taken another approach and simply moved its internals (assignments, loans, moves) up, but this would have required more processing to be done within the compiler. I took the current approach because it was simplest based on how the borrow checker structures its data and required the least transformations.
Naming things is not my strong suit, so I'm very willing to change this name to something clearer, or restructuring the structs if that makes more sense.
This comment has been minimized.
This comment has been minimized.
nrc
Jun 6, 2017
Member
OK, cool. Then maybe per_fn_borrows rather than just borrows for the field name? I think I prefer BorrowData rather than Borrows.
This comment has been minimized.
This comment has been minimized.
| @@ -240,3 +242,59 @@ pub struct SigElement { | |||
| pub start: usize, | |||
| pub end: usize, | |||
| } | |||
|
|
|||
| #[derive(Debug, Clone, RustcDecodable, RustcEncodable)] | |||
| pub struct Borrows { | |||
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
| #[derive(Debug, Clone, RustcDecodable, RustcEncodable)] | ||
| pub struct Borrows { | ||
| pub ref_id: Id, | ||
| pub assignments: Vec<Assignment>, |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Nashenas88
Jun 6, 2017
Author
Contributor
I use this to help display the "scope" (Niko's terminology) of the variable. The start of the scope is the low byte of the assignment's kill span (represented by just span here), and the end is either the high byte of the assignment span, or the high byte of span of the first move for this variable. I checked with @pnkfelix on irc some time ago to make sure this was valid, and he thought it matched existing compiler behavior.
This comment has been minimized.
This comment has been minimized.
nrc
Jun 6, 2017
Member
Could we explicitly store that span, rather than compute it from assignments?
This comment has been minimized.
This comment has been minimized.
Nashenas88
Jun 6, 2017
Author
Contributor
This exact span isn't stored anywhere. The borrow checking code does not hold on to those values during its passes. I spent quite some time making sure because I felt uncomfortable doing the computing myself. It was only after @pnkfelix reassured me that this matched the behavior that I was ok moving forward.
Though, I could do this computation early. I just thought of a way to do it more efficiently than sorting. My original impl filtered all moves by matching ref_id, then sorted by their span's lo byte, then just used the first item. I could instead fold all moves into a hashmap with the ref ids as keys, swapping the entry if the new move has a lower lo byte. This should run in O(n) time, and I already run in O(n) when mapping. I was initially worried about the cost of doing this for all assignments in a crate. If I do early computation it would also make this more compatible with the EndRegion changes for Mir borrow checking...
This comment has been minimized.
This comment has been minimized.
nrc
Jun 6, 2017
Member
Ah so, you compute the 'scope span' on the fly and that depends on some assignments and some other data for a variable (loans?). So either we compute this in the compiler and pass the span explicitly, but don't need to pass assignments and moves, or we pass a load of data and compute in the tool, which gives a faster save-analysis? Do you have an idea for how long it will take to do this in the compiler? I would prefer to do the compiler option and plan to do this on demand in the near future, rather than do this in the RLS.
This comment has been minimized.
This comment has been minimized.
Nashenas88
Jun 6, 2017
Author
Contributor
The 'scope span' depends on an assignment and the related moves. Loans are ignored for this purpose, we still try to visualize even non-compiling code (preparing for an idea where this gets used to display compilation errors). Then I wouldn't need to send the full assignment, just the span with the matching ref_id. The moves are still needed because those are visualized (in non-compiling code where someone attempted to move twice).
This comment has been minimized.
This comment has been minimized.
Nashenas88
Jun 6, 2017
Author
Contributor
I'm not sure how long this will take in the compiler, but the more I think about it the more I think it won't be a big burden (unless maybe we're talking about something like servo... that's where I really become unsure). I think there'd be on average (just guessing, no data) a 1:1 ratio of assignments to moves (maybe more as not all assignments have moves). I don't expect high move to assignment ratio because that would mean a lot of non-compiling code
| } | ||
|
|
||
| #[derive(Debug, Clone, RustcDecodable, RustcEncodable)] | ||
| pub enum CauseData { |
This comment has been minimized.
This comment has been minimized.
nrc
Jun 6, 2017
Member
I would not, at least at first. I would start with a very simple system, then add stuff.
|
|
||
| #[derive(Debug, Clone, RustcDecodable, RustcEncodable)] | ||
| pub struct Loan { | ||
| pub ref_id: Id, |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Nashenas88
Jun 6, 2017
Author
Contributor
They point to the original assignment that is being borrowed from. It's like the def in goto_def, but for borrows and moves.
This comment has been minimized.
This comment has been minimized.
Nashenas88
Jun 6, 2017
Author
Contributor
They may not be as necessary as I thought. I'll have to follow up on the ide extension prototypes to see if I needed to use those, or if that was just something needed for the original filtering. If we don't keep the Borrows struct, and only maintain the loans, moves, etc. in the analysis struct, then they will be necessary because that's what will be used to find the matching loans, moves, etc given the def_id for a span. Based on this, should I have named them def_id instead?
This comment has been minimized.
This comment has been minimized.
nrc
Jun 6, 2017
Member
I'm not sure what "original assignment" means. Is it where the variable is declared? I think it can't be since it is values that are borrowed, not variables? Could you give an example please?
This comment has been minimized.
This comment has been minimized.
Nashenas88
Jun 6, 2017
Author
Contributor
Sorry, I am responding while too tired and was also thinking about the front-end implementation too much. I had intended to mean the variable declaration since the prototypes only tracked borrows and moves from a variable declaration selected by the cursor. I hadn't attempted to show borrows of borrows yet (mostly because I hadn't figured out how to cleanly visualize that). Here the ref_ids point to the value that is being borrowed. I'm about to head to bed so I'll add examples tomorrow morning (US Eastern morning).
This comment has been minimized.
This comment has been minimized.
|
Looks like I'll be quite busy tonight. I'm going to get to work on the changes tomorrow evening instead. |
This comment has been minimized.
This comment has been minimized.
|
So trying to incorporate the latest changes into the compiler, and I'm getting:
Is the compiler not on the latest |
This comment has been minimized.
This comment has been minimized.
|
It is not. This PR puts it on the latest version - rust-lang/rust#42471. Hopefully it will land soon. |
This comment has been minimized.
This comment has been minimized.
|
I believe I addressed all concerns in the comments. Switching to track |
This comment has been minimized.
This comment has been minimized.
|
Cool, thanks for the changes! |
nrc
merged commit 0cf8072
into
rust-dev-tools:master
Jun 18, 2017
This comment has been minimized.
This comment has been minimized.
|
Should I have bumped the crate version for this? |
This comment has been minimized.
This comment has been minimized.
Yes, basically any change is a breaking change here because we use the data structures with transmute |
This comment has been minimized.
This comment has been minimized.
|
Sorry, to clarify, the crate version needs bumping to publish, you don't need to do it, I'm happy to do so (I thought you had, but I mistook cargo.lock for cargo.toml). tl;dr you can bump if you like, it doesn't matter either way :-) And I just published v0.7 with these changes. |
Nashenas88 commentedJun 4, 2017
Initial changes to support borrow/ownership visualization through rls.