-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Introduce "obligation forest" data structure into fulfillment to track backtraces #30533
Conversation
6f9dd59
to
bdc1c61
Compare
Cc @jroesch |
This looks pretty nice from the big-picture view. |
☔ The latest upstream changes (presumably #30582) made this pull request unmergeable. Please resolve the merge conflicts. |
@nikomatsakis I think that this is mostly compatible with the branch I have laying around that moves more RefCells, and the fulfillment context into the inference context. I would like to integrate this into my branch and move forward if possible, let's talk when you are back from the holidays 😄 overall 👍 |
Actually as I'm looking this over this is perfect. I just had some unfinished code around the SnapshotTree. I should be able to replace the SnapshotTree with this on my branch and end up with a fully transactional inference context. |
fd9bf8f
to
cede41a
Compare
OK, I've done a reviewing pass through this series of commits, and it all looks great to me. I left a number of small nits mostly about making a few things more clear in the new forest code. It's fine by me to do 4 and 5 separately. I'd be willing to help with that work, as well. |
@aturon OK, so, I have to go through your nits (and rebase), but the current HEAD of 3423caae956ce8d3525baf3bf5ec7e689339765d builds and passes
(These are in addition to the points I raised in the intro about better error messages, transactional support, etc.) |
I wonder if I should measure the impact on crater. I found very little impact (none?) in libstd/rustc, but a few test cases were affected. We could probably retool the code to issue warnings rather than abort by having a cycle be detected and then issue a warning and drop the new obligation. |
The other thing I have not done which may be worth doing is measuring the impact on performance. |
db09897
to
bb0fdf8
Compare
@aturon ok I cleaned up the commit history some. I left in the WIP commits that are just tiny things I will rebase in. Otherwise, ready for r? on the remaining commits. Then I'll rebase, open the aforementioned FIXME issue, and land. |
I am thinking now that, before landing, I ought to modify this code so that it issues warnings on cycles if they do not consist solely of co-inductive traits (but accepts them). Seems like a prudent step. It would also be nice to do a crater run to get an idea of what patterns might be affected in the wild. |
bb0fdf8
to
bc309c4
Compare
I measured performance on libsyntax. Before: 1.4% performance difference. Pretty minor, I'm sure it can be improved over time as well. |
stalled rather than keeping this annoying mark; I checked that the original compile-time regression that the mark was intended to fix (rust-lang#18208) was still reasonable, but I've not done exhaustive measurements to see how important this "optimization" really is anymore
this commit won't build because, as of this version, no coinductive reasoning at all is really supported
bc309c4
to
60c302f
Compare
Good news. A crater report shows ZERO regressions. |
Reviewed the recent string of commits. LGTM! Note tidy error. |
So now the only question is: land this immediately, or wait for beta to be cut? |
Given the successful crater run, I guess I might as well land it. |
I found one test that still permits #29859 even under this branch, but I think the real error here is that the OIBIT orphan rules are not being correctly enforced. I'm actually in the process of writing up a more precise OIBIT specification that would make this clearer: #![feature(optin_builtin_traits)]
trait Magic: Copy {}
impl Magic for .. {}
impl<T:Magic> Magic for T {}
fn copy<T: Magic>(x: T) -> (T, T) { (x, x) }
#[derive(Debug)]
struct NoClone;
fn main() {
let (a, b) = copy(NoClone); //~ ERROR E0277
println!("{:?} {:?}", a, b);
} |
I take it back. I think that this example can be transformed into one indicates why co-inductive semantics are broken, even for OIBIT traits. However, it is still true that the document I've been working -- which tries to elaborate an alternative to those coinductive semantics -- ought to address this problem. In other words, I think this patch transforms the issue into a (smaller) issue with OIBIT trait impls. But it does not fix #29859 |
…not fully fixed.
527cdc3
to
4fbb71f
Compare
@bors r=aturon |
📌 Commit 4fbb71f has been approved by |
This PR introduces an `ObligationForest` data structure that the fulfillment context can use to track what's going on, instead of the current flat vector. This enables a number of improvements: 1. transactional support, at least for pushing new obligations 2. remove the "errors will be reported" hack -- instead, we only add types to the global cache once their entire subtree has been proven safe. Before, we never knew when this point was reached because we didn't track the subtree. - this in turn allows us to limit coinductive reasoning to structural traits, which sidesteps #29859 3. keeping the backtrace should allow for an improved error message, where we give the user full context - we can also remove chained obligation causes This PR is not 100% complete. In particular: - [x] Currently, types that embed themselves like `struct Foo { f: Foo }` give an overflow when evaluating whether `Foo: Sized`. This is not a very user-friendly error message, and this is a common beginner error. I plan to special-case this scenario, I think. - [x] I should do some perf. measurements. (Update: 2% regression.) - [x] More tests targeting #29859 - [ ] The transactional support is not fully integrated, though that should be easy enough. - [ ] The error messages are not taking advantage of the backtrace. I'd certainly like to do 1 through 3 before landing, but 4 and 5 could come as separate PRs. r? @aturon // good way to learn more about this part of the trait system f? @arielb1 // already knows this part of the trait system :)
…, r=aturon" This reverts commit c14b615, reversing changes made to dda25f2. This caused a regression in compiler performance and backporting the fix to beta was deemed too risky and too challenging, since it is non-trivial and builds on prior commits in various ways. Conflicts: src/librustc/middle/traits/fulfill.rs src/librustc_data_structures/lib.rs
Add a per-tree error cache to the obligation forest This implements part of what @nikomatsakis mentioned in #30533 (comment): > 1. If you find that a new obligation is a duplicate of one already in the tree, the proper processing is: > * if that other location is your parent, you should abort with a cycle error (or accept it, if coinductive) > * if that other location is not an ancestor, you can safely ignore the new obligation In particular it implements the "if that other location is your parent accept it, if coinductive" part. This fixes #40827. I have to say that I'm not 100% confident that this is rock solid. This is my first pull request 🎉, and I didn't know anything about the trait resolver before this. In particular I'm not totally sure that comparing predicates is enough (for instance, do we need to compare `param_env` as well?). Also, I'm not sure what @nikomatsakis mentions [here](#30977 (comment)), but it might be something that affects this PR: > In particular, I am wary of getting things wrong around inference variables! We can always add things to the set in their current state, and if unifications occur then the obligation is just kind of out-of-date, but I want to be sure we don't accidentally fail to notice that something is our ancestor. I decided this was subtle enough to merit its own PR. Anyway, go ahead and review 🙂. Ref #30977. # Performance We are now copying vectors around, so I decided to do some benchmarking. A simple benchmark shows that this does not seem to affect performance in a measurable way: I ran `cargo clean && cargo build` 20 times on actix-web (84b27db) and these are the results: ```text rustc master: Mean Std.Dev. Min Median Max real 66.637 2.996 57.220 67.714 69.314 user 307.293 14.741 258.093 312.209 320.702 sys 12.524 0.653 10.499 12.726 13.193 rustc fix-bug-overflow-send: Mean Std.Dev. Min Median Max real 66.297 4.310 53.532 67.516 70.348 user 306.812 22.371 236.917 314.748 326.229 sys 12.757 0.952 9.671 13.125 13.544 ``` I will do a more comprehensive benchmark (compiling rustc stage1) and post the results. r? @nikomatsakis, @nnethercote PS: It is better to review this commit-by-commit.
This PR introduces an
ObligationForest
data structure that the fulfillment context can use to track what's going on, instead of the current flat vector. This enables a number of improvements:This PR is not 100% complete. In particular:
struct Foo { f: Foo }
give an overflow when evaluating whetherFoo: Sized
. This is not a very user-friendly error message, and this is a common beginner error. I plan to special-case this scenario, I think.I'd certainly like to do 1 through 3 before landing, but 4 and 5 could come as separate PRs.
r? @aturon // good way to learn more about this part of the trait system
f? @arielb1 // already knows this part of the trait system :)