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

first pass at isolating dep-graph tasks #40308

Merged
merged 2 commits into from
Mar 11, 2017

Conversation

nikomatsakis
Copy link
Contributor

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!

@nikomatsakis
Copy link
Contributor Author

r? @michaelwoerister

cc @eddyb

cc #40304

@rust-highfive
Copy link
Collaborator

r? @nrc

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive assigned michaelwoerister and unassigned nrc Mar 6, 2017
@nikomatsakis
Copy link
Contributor Author

nikomatsakis commented Mar 6, 2017

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 tcx, which is basically always necessary.

@michaelwoerister
Copy link
Member

Another possibility is always passing the tcx, which is basically always necessary.

If that's possible it would make for a rather simple API.

@eddyb
Copy link
Member

eddyb commented Mar 7, 2017

@nikomatsakis That RFC is already implemented! We'll be able to use it once we bump the beta.

@nikomatsakis
Copy link
Contributor Author

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.

@nikomatsakis nikomatsakis changed the title WIP: first pass at isolating dep-graph tasks first pass at isolating dep-graph tasks Mar 7, 2017
@nikomatsakis
Copy link
Contributor Author

removing "WIP" as I think this is ready for review

r? @michaelwoerister

Copy link
Member

@michaelwoerister michaelwoerister left a 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.

@@ -15,6 +15,8 @@ mod edges;
mod graph;
mod query;
mod raii;
#[macro_use]
Copy link
Member

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.

@@ -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
Copy link
Member

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.


use super::graph::DepGraph;

/// The `DepGraphSafe` auto trait is used to specify what kinds of
Copy link
Member

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point :)

@@ -70,6 +70,7 @@ mod macros;
pub mod diagnostics;

pub mod cfg;
#[macro_use]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed anymore?

Copy link
Contributor Author

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);
Copy link
Member

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.

Copy link
Contributor Author

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.

@nikomatsakis
Copy link
Contributor Author

@bors r=mw

@bors
Copy link
Contributor

bors commented Mar 8, 2017

📌 Commit 19c6bfb has been approved by mw

@bors
Copy link
Contributor

bors commented Mar 9, 2017

🔒 Merge conflict

@alexcrichton
Copy link
Member

@bors: retry

alexcrichton added a commit to alexcrichton/rust that referenced this pull request Mar 10, 2017
…, 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!
@alexcrichton
Copy link
Member

@bors: r=mw

@bors
Copy link
Contributor

bors commented Mar 10, 2017

📌 Commit 4d5441f has been approved by mw

alexcrichton added a commit to alexcrichton/rust that referenced this pull request Mar 10, 2017
…, 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!
@bors
Copy link
Contributor

bors commented Mar 11, 2017

⌛ Testing commit 4d5441f with merge 4b1dfbd...

bors added a commit that referenced this pull request Mar 11, 2017
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!
@bors
Copy link
Contributor

bors commented Mar 11, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: mw
Pushing 4b1dfbd to master...

@bors bors merged commit 4d5441f into rust-lang:master Mar 11, 2017
@nikomatsakis nikomatsakis deleted the incr-comp-isolate-task branch April 14, 2017 10:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants