-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
first pass at isolating dep-graph tasks #40308
Conversation
r? @nrc (rust_highfive has picked a reviewer for you, use r? to override) |
This is probably not ready to merge quite yet, but I wanted to let people take a look and get some feedback. I'm thinking of experimenting with different forms for more ergonomic APIs. I had thoughts of experimenting with macros that create functions, though it might be better to take advatnage of the new "coerce closure into fn ptr" RFC, once that is implemented. Another possibility is always passing the |
If that's possible it would make for a rather simple API. |
@nikomatsakis That RFC is already implemented! We'll be able to use it once we bump the beta. |
OK, pushed a revised version that takes a fn with two arguments. This might get mildly cleaner if we had access to the closure-as-fn thing (good to hear that will come soon, @eddyb) but, actually, I think not that much. Declaring a fn item just isn't that bad, and for those cases where it is, it starts to suggest places that we should be employing on-demand, I think. |
removing "WIP" as I think this is ready for review |
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 a good starting point. Closure-to-fn coercions will certainly make this more ergonomic.
r=me with the comments addressed.
src/librustc/dep_graph/mod.rs
Outdated
@@ -15,6 +15,8 @@ mod edges; | |||
mod graph; | |||
mod query; | |||
mod raii; | |||
#[macro_use] |
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 don't see any macros in that module.
src/librustc/dep_graph/graph.rs
Outdated
@@ -76,11 +77,13 @@ impl DepGraph { | |||
op() | |||
} | |||
|
|||
pub fn with_task<OP,R>(&self, key: DepNode<DefId>, op: OP) -> R | |||
where OP: FnOnce() -> R | |||
pub fn with_task<C, A, R>(&self, key: DepNode<DefId>, cx: C, arg: A, task: fn(C, A) -> R) -> R |
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.
A comment explaining the setup would be good here, especially why there's a distinction between cx
and arg
.
src/librustc/dep_graph/safe.rs
Outdated
|
||
use super::graph::DepGraph; | ||
|
||
/// The `DepGraphSafe` auto trait is used to specify what kinds of |
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 not an auto trait anymore, right?
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.
good point :)
src/librustc/lib.rs
Outdated
@@ -70,6 +70,7 @@ mod macros; | |||
pub mod diagnostics; | |||
|
|||
pub mod cfg; | |||
#[macro_use] |
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.
Not needed anymore?
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 all the macro stuff is from an older pass, thanks
let def_id = self.tcx.hir.local_def_id(id); | ||
self.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), || { | ||
self.tcx.hir.read(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.
This explicit read is not there anymore in the new version. This should be fine -- after all, the new system should guarantee that we cannot do anything with the NodeId without triggering a read -- but I wanted to double check that that is intentional.
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 is intentional -- the newer code no longer "leaks" in a hir::Item
(or TraitItem
, etc), so there is no need for the "automatic" read.
635a4c1
to
19c6bfb
Compare
@bors r=mw |
📌 Commit 19c6bfb has been approved by |
🔒 Merge conflict |
@bors: retry |
…, r=mw first pass at isolating dep-graph tasks This intentionally leaves `DepGraph::in_task()`, the more common form, alone. Eventually all uses of `DepGraph::in_task()` should be ported to `with_task()`, but I wanted to start with a smaller subset. I also used `AssertDepGraphSafe` on the closures that are found in trans. This is because the types there are non-trivial and I wanted to lay down the mechanism and come back to the more subtle cases. The current approach taken in this PR has a downside: it is necessary to manually "reify" fn types into fn pointers when starting a task, like so: dep_graph.with_task(..., task_fn as fn(_)) this is because `with_task` takes some type `T` that implements `DepGraphTask` rather than taking a `fn()` type directly. *This* is so that we can accept closure and also so that we can accept fns with multiple arities. I am not sure this is the right approach. Originally I wanted to use closures bound by an auto trait, but that approach has some limitations: - the trait cannot have a `read()` method; since the current method is unused, that may not be a problem. - more importantly, we would want the auto trait to be "undefined" for all types *by default* -- that is, this use case doesn't really fit the typical auto trait scenario. For example, imagine that there is a `u32` loaded out of a `hir::Node` -- we don't really want to be passing that `u32` into the task!
A task function is now given as a `fn` pointer to ensure that it carries no state. Each fn can take two arguments, because that worked out to be convenient -- these two arguments must be of some type that is `DepGraphSafe`, a new trait that is intended to prevent "leaking" information into the task that was derived from tracked state. This intentionally leaves `DepGraph::in_task()`, the more common form, alone. Eventually all uses of `DepGraph::in_task()` should be ported to `with_task()`, but I wanted to start with a smaller subset. Originally I wanted to use closures bound by an auto trait, but that approach has some limitations: - the trait cannot have a `read()` method; since the current method is unused, that may not be a problem. - more importantly, we would want the auto trait to be "undefined" for all types *by default* -- that is, this use case doesn't really fit the typical auto trait scenario. For example, imagine that there is a `u32` loaded out of a `hir::Node` -- we don't really want to be passing that `u32` into the task!
19c6bfb
to
4d5441f
Compare
@bors: r=mw |
📌 Commit 4d5441f has been approved by |
…, r=mw first pass at isolating dep-graph tasks This intentionally leaves `DepGraph::in_task()`, the more common form, alone. Eventually all uses of `DepGraph::in_task()` should be ported to `with_task()`, but I wanted to start with a smaller subset. I also used `AssertDepGraphSafe` on the closures that are found in trans. This is because the types there are non-trivial and I wanted to lay down the mechanism and come back to the more subtle cases. The current approach taken in this PR has a downside: it is necessary to manually "reify" fn types into fn pointers when starting a task, like so: dep_graph.with_task(..., task_fn as fn(_)) this is because `with_task` takes some type `T` that implements `DepGraphTask` rather than taking a `fn()` type directly. *This* is so that we can accept closure and also so that we can accept fns with multiple arities. I am not sure this is the right approach. Originally I wanted to use closures bound by an auto trait, but that approach has some limitations: - the trait cannot have a `read()` method; since the current method is unused, that may not be a problem. - more importantly, we would want the auto trait to be "undefined" for all types *by default* -- that is, this use case doesn't really fit the typical auto trait scenario. For example, imagine that there is a `u32` loaded out of a `hir::Node` -- we don't really want to be passing that `u32` into the task!
⌛ Testing commit 4d5441f with merge 4b1dfbd... |
first pass at isolating dep-graph tasks This intentionally leaves `DepGraph::in_task()`, the more common form, alone. Eventually all uses of `DepGraph::in_task()` should be ported to `with_task()`, but I wanted to start with a smaller subset. I also used `AssertDepGraphSafe` on the closures that are found in trans. This is because the types there are non-trivial and I wanted to lay down the mechanism and come back to the more subtle cases. The current approach taken in this PR has a downside: it is necessary to manually "reify" fn types into fn pointers when starting a task, like so: dep_graph.with_task(..., task_fn as fn(_)) this is because `with_task` takes some type `T` that implements `DepGraphTask` rather than taking a `fn()` type directly. *This* is so that we can accept closure and also so that we can accept fns with multiple arities. I am not sure this is the right approach. Originally I wanted to use closures bound by an auto trait, but that approach has some limitations: - the trait cannot have a `read()` method; since the current method is unused, that may not be a problem. - more importantly, we would want the auto trait to be "undefined" for all types *by default* -- that is, this use case doesn't really fit the typical auto trait scenario. For example, imagine that there is a `u32` loaded out of a `hir::Node` -- we don't really want to be passing that `u32` into the task!
☀️ Test successful - status-appveyor, status-travis |
This intentionally leaves
DepGraph::in_task()
, the more common form,alone. Eventually all uses of
DepGraph::in_task()
should be portedto
with_task()
, but I wanted to start with a smaller subset.I also used
AssertDepGraphSafe
on the closures that are found intrans. This is because the types there are non-trivial and I wanted to
lay down the mechanism and come back to the more subtle cases.
The current approach taken in this PR has a downside: it is necessary
to manually "reify" fn types into fn pointers when starting a task,
like so:
this is because
with_task
takes some typeT
that implementsDepGraphTask
rather than taking afn()
type directly. This is sothat we can accept closure and also so that we can accept fns with
multiple arities. I am not sure this is the right approach.
Originally I wanted to use closures bound by an auto trait, but that
approach has some limitations:
read()
method; since the current methodis unused, that may not be a problem.
by default -- that is, this use case doesn't really fit the typical
auto trait scenario. For example, imagine that there is a
u32
loadedout of a
hir::Node
-- we don't really want to be passing thatu32
into the task!