-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Separate function bodies from their signatures in HIR #37918
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @nikomatsakis (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, this is looking really good! I had a few comments as to possible other ways that we could do things. I'm not sure which, if any, we should do before landing. I might have to experiment locally to form a real opinion in any case. Curious to get your opinion. These are the major themes I remember:
- use a separate method for determining whether to visit bodies or not?
- should we use
DepNode::HirBody
, or else give def-ids to fn bodies and useDepNode::Hir
? - how to fix the collect edges? -- pushed some commits into the branch that fix it
I have some thoughts on the last one, but I think it'd be easier for me to just experiment locally and send you a diff if what I am saying makes sense. =)
impl<'v> Visitor<'v> for IdRangeComputingVisitor { | ||
impl<'a, 'ast> Visitor<'ast> for IdRangeComputingVisitor<'a, 'ast> { | ||
fn nested_visit_map(&mut self) -> Option<(&Map<'ast>, NestedVisitMode)> { | ||
Some((&self.map, NestedVisitMode::OnlyBodies)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, of course... in our latest comments on the issue, I had forgotten the central problem where you want to visit fn bodies as the default, but of course we don't have the map by default... my inclination is to make the nested_body_map
be a separate method, and make it have no default implementation, so that we always specify it for every visitor. I feel like it is potentially much more surprising to skip over bodies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Plus then we can avoid the NestedVisitMode
tuple)
self.handle(|i: ItemFnParts<'a>| i.body, | ||
|_, _, _: &'a ast::MethodSig, _, body: ast::ExprId, _, _| body, | ||
|c: ClosureParts<'a>| c.body) | ||
} | ||
|
||
pub fn decl(self) -> &'a FnDecl { | ||
if let map::NodeInlinedItem(&InlinedItem { kind: InlinedItemKind::Fn(ref decl), .. }) = self.node { | ||
return &decl; | ||
} | ||
self.handle(|i: ItemFnParts<'a>| &*i.decl, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like the most natural way to extend this code would be extend handle
to cover this case, probably by adding a fourth closure callback (inlined-item).
fn_like.body(), | ||
fn_like.span(), | ||
fn_like.id()); | ||
let qualif = match self.tcx.const_qualif_map.borrow_mut().entry(fn_like.body().node_id()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is happening here? Is this populated for inlined items or something? At minimum, some comments seem good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yeah. Because the FnLike
interface is only half implemented for inlined items, the fn_like
call would fail for them, but the const_qualif_map
is already populated for them, so I added the check beforehand. I'll need to clean that up somehow...
Item(DefId /* def-id in source crate */, P<hir::Item>), | ||
TraitItem(DefId /* impl id */, P<hir::TraitItem>), | ||
ImplItem(DefId /* impl id */, P<hir::ImplItem>) | ||
pub struct InlinedItem { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's hard for me to assess if this is the best way -- vs say trying to encode the fn bodies separately. Apart from some nits (which I tried to cite), it does seem a bit cleaner than what was here before, though. Perhaps @eddyb has an opinion. But overall I think I like it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems okay - shouldn't need the type of a constant though, in fact, you should be able to only record a Vec<DefId>
for the arguments of a const fn
, which doesn't even need to be in a separate enum anymore, just replace the kind
field with const_fn_args: Vec<DefId>
and that should be that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would make implementing FnLike
even harder, though, I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You shouldn't need to implement FnLike
though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lookup_const_fn_by_id
returns an FnLikeNode
currently. But I guess it could return something else, e.g. a new enum?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that would make more sense, FnLikeNode
is more about pretty-printing.
@@ -42,6 +42,9 @@ pub enum DepNode<D: Clone + Debug> { | |||
// Represents the HIR node with the given node-id | |||
Hir(D), | |||
|
|||
// Represents the body of a function or method | |||
HirBody(D), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment should specify that D
is the def-id of the fn/method, as opposed to the id of the body itself.
As an alternative, we could get rid of this variant and give expression bodies their own def-id. Not yet sure which approach I prefer, have to read more.
@@ -31,7 +31,7 @@ mod x { | |||
mod y { | |||
use x; | |||
|
|||
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] | |||
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice =)
fn col_same() { | ||
let _ = column!(); | ||
} | ||
|
||
#[rustc_clean(label="Hir", cfg="rpass2")] | ||
#[rustc_clean(label="HirBody", cfg="rpass2")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like it'd be good to have both Hir
and HirBody
here?
@@ -144,6 +144,7 @@ impl<'a> InlinedItemRef<'a> { | |||
pub fn from_trait_item(def_id: DefId, item: &'a hir::TraitItem, _map: &hir_map::Map) -> InlinedItemRef<'a> { | |||
let (body, kind) = match item.node { | |||
hir::ConstTraitItem(ref ty, Some(ref body)) => (&**body, InlinedItemKindRef::Const(ty)), | |||
hir::ConstTraitItem(_, None) => bug!("InlinedItemRef::from_trait_item called for const without body"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a pre-existing bug, or something you introduced?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code which calls from_trait_item
takes care to only call it when there's a body, but I accidentally changed that once, and it wasn't immediately clear to me what I'd done wrong, so I just added this special message in case it happens again.
fn visit_item(&mut self, item: &hir::Item) { | ||
impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { | ||
fn nested_visit_map(&mut self) -> Option<(&hir::map::Map<'tcx>, NestedVisitMode)> { | ||
Some((&self.ccx.tcx.map, NestedVisitMode::OnlyBodies)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, this is suboptimal from the POV of the dep-graph tasks. We don't want the task which writes to the signature of a fn also reading from the fn body. Not sure what's the best way to tweak that just now; it's certainly possible.
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")] | ||
pub fn y() { | ||
x::x(); | ||
// FIXME: This should be clean |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the problem is the issue of collect reading from the fn body that I pointed out earlier.
Giving def-ids to bodies didn't really occur to me (I was thinking only definitions can have def-ids). That would probably make a few things cleaner, but I don't really have the perspective to know what else it may complicate. Also, how would the testing attributes work? Can you give attributes to expressions? |
@flodiebold so I pushed two commits into your branch -- take a look. The first one fixes the |
You can give attributes to statements, not expressions. So that is a possible complication; I guess we could look for an attribute on the first statement of a block or something. |
@flodiebold all in all, the main thing I'd prefer to settle now is the visitor trait -- i.e., whether to have another method. The |
☔ The latest upstream changes (presumably #37642) made this pull request unmergeable. Please resolve the merge conflicts. |
@nikomatsakis It does seem to me like having two methods and having no default for I'll fix the remaining tests; I think they may have come in during my last rebase, after which I forgot to check them again :) |
Great =) If that change is made and tests are working, I think this PR is ready to go. We can revisit the |
@eddyb I refactored the inlined item handling again. I didn't get rid of the @nikomatsakis Ok, I think I've addressed everything. |
@michaelwoerister By the way, the |
@flodiebold Good catch. Yes, maybe we can let the rest runner do some checks to prevent this. |
☔ The latest upstream changes (presumably #37676) made this pull request unmergeable. Please resolve the merge conflicts. |
@flodiebold The commit "Merge master into separate-bodies" is worrying me - did you |
@eddyb I did merge because I wasn't sure whether a merge or a rebase is the preferred way to resolve conflicts. But I've actually just done a rebase onto the current master, so I could push that too. Apart from that, I think the PR is ready and just needs to be looked at again. |
@flodiebold Rebase + force push is the way, only @bors does merges (into the |
Ok, that's what I preferred anyway. Rebased version coming up. |
cd9e807
to
5162288
Compare
@flodiebold I was experimenting with an alternative version of the visitor refactoring. I've just rebased it atop your rebase, once it builds I'll push it to your branch and you can tell me what you think. It's actually sort of closer to your original approach. |
done. |
Pushed one more commit updating the comments a bit. |
@flodiebold (if you are happy with my latest commit, then r=me on the PR) |
Ah, that does seem nicer. Makes it easier to search for visitors which currently don't return a map, too. 👍 |
@bors r+ |
📌 Commit f620072 has been approved by |
@bors r- failed Travis ( |
☔ The latest upstream changes (presumably #37791) made this pull request unmergeable. Please resolve the merge conflicts. |
They don't implement FnLikeNode anymore, instead are handled differently further up in the call tree. Also, keep less information (just def ids for the args).
... and make the latter mandatory to implement.
f620072
to
bc9bae9
Compare
bc9bae9
to
593b273
Compare
@eddyb @nikomatsakis Fixed and rebased :) |
@bors r=nikomatsakis |
📌 Commit 593b273 has been approved by |
Separate function bodies from their signatures in HIR Also give them their own dep map node. I'm still unhappy with the handling of inlined items (1452edc1), but maybe you have a suggestion how to improve it. Fixes #35078. r? @nikomatsakis
@flodiebold great, thanks! |
annotate stricter lifetimes on LateLintPass methods to allow them to forward to a Visitor this unblocks clippy (rustup blocked after #37918) clippy has lots of lints that internally call an `intravisit::Visitor`, but the current lifetimes on `LateLintPass` methods conflicted with the required lifetimes (there was no connection between the HIR elements and the `TyCtxt`) r? @Manishearth
[10/n] Split constants and functions' arguments into disjoint bodies. _This is part of a series ([prev](#38053) | [next]()) of patches designed to rework rustc into an out-of-order on-demand pipeline model for both better feature support (e.g. [MIR-based](https://github.com/solson/miri) early constant evaluation) and incremental execution of compiler passes (e.g. type-checking), with beneficial consequences to IDE support as well. If any motivation is unclear, please ask for additional PR description clarifications or code comments._ <hr> Finishes the signature-body split started in #37918, namely: * `trait` items are separated just like `impl` items were, for uniformity, closing #37712 * `static`s, `const`s (including associated ones), `enum` discriminants and array lengths get bodies * even the count in "repeat expressions", i.e. `n` in `[x; n]`, which fixes #24414 * arguments' patterns are moved to the bodies, with the types staying in `FnDecl` * `&self` now desugars to `self: &Self` instead of `self: &_` (similarly for other `self` forms) * `astconv`'s and metadata's (for rustdoc) informative uses are explicitly ignored for the purposes of the dep graph. this could be fixed in the future by hashing the exact information being extracted about the arguments as opposed to generating a dependency on *the whole body*
Also give them their own dep map node.
I'm still unhappy with the handling of inlined items (1452edc1), but maybe you have a suggestion how to improve it.
Fixes #35078.
r? @nikomatsakis