-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
backtrack if can not activate #5000
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
Oh dear that's a bummer! It seems like a lot of roads are pointing towards error messages not being that great... This one I would say though yeah is even more pressing than |
Is there some way to print a error just as we would have but then continue
processing, if so I have a bunch of ideas for how to improve error
messages, at least in this case.
Or is there some way to tie an an error message to a previous one. So we
can say options for dependent b causes include...
…On Feb 2, 2018 6:10 PM, "Alex Crichton" ***@***.***> wrote:
Oh dear that's a bummer! It seems like a lot of roads are pointing towards
error messages not being that great...
This one I would say though yeah is even more pressing than links in that
this comes up quite frequently (typos and such). In that sense it'd be
pretty bad if we regressed this error message :(
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#5000 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/ADiaQDfACrexbHlxNdx5FQGjornubYrVks5tQ5XxgaJpZM4R2Pge>
.
|
It will take some work to rebase/merge this with #4834, and that is a much bigger/more common UX improvement. I think this should be put on hold for that to land and for a plan for error messages to be developed. |
@Eh2406 certainly! Unfortunately I don't really know how to precisely proceed. I do have a feeling, though, for how to proceed generally! So prior to #4978 we had a custom error message for the As to how to get there... I'm not sure. I think it may also be worth taking a step back and looking at the resolution algorithm from a distance too. Right now Cargo in theory attempts all possible crate resolution graphs. I mean like all possible graphs. This can put us in one of two situations:
Here we're most interested in the latter situation, but it also means there's no one error for us to return. In some sense we tried everything and it could have all failed for a number of reasons. I think we could probably optimize to return the "shortest" error perhaps? (for whatever definition "shortest" actually means) There's also the separate bug that Cargos' backtracking and exploration of the problem space takes forever, but hopefully #4834 can help with that! Hm so that's unfortunately not super actionable, but is that helpful at least to get started? |
Thanks for the pointer to the I think it may be useful to break it down into more situations.
We should keep in mind that the most common reason for any kind of error is a simple typo. The first time we discover that the tree is not trivial we are in the state closest to the user's mental model of just take the newest version of everything. And almost anything we print will be helpful in discovering that it is just a typo. So I think we should print a good causal chain for the backtracking to the user, and continue in the serch. Another huristick if something deep in our tree is unsolvable, then we probably hit almost the same error message lots of times. For example We depend on A=* (with 100 versions to choose from) which depends on B=* (with 100 versions to choose from) which depends on C=* all versions have been yanked, If we printed all errors (a thout experiment) We will have 10k "can't find a candidate for C ...." and just 100 "can't find a candidate for B ...." and 1 "can't find a candidate for A ...." The most common one is the most helpful. So maybe 10 minutes into resolution we can print "we are still working on finding something that works but, here are the 3 most often encountered difficulties:" each with a full a good causal chain for the backtracking. All of these thoughts depend on being able to print the message as part of some context, and then continue with the serch. How do I do that? I could make a function that returns the errors as strings. But the words "errors as strings" makes me very nervous. |
All excellent points! I think we should take it as an assumption that if we're going to produce a human readable error then we can reach that conclusion in a reasonable amount of time. In that sense I hope that #4834 will get us closer to that goal but we may have other bugs of "Cargo goes in the weeds too much". I don't think, though, that such a situation should impact the design of the error messages here. Now I will say we have two other tricks up our sleeve for "gee resolution is taking forever":
In that sense I think your second and third cases would fold into one another. I definitely agree that mistakes tend to be common typos before we get to serious "oh dear what to do" scenarios. Despite that though if Cargo is indeed successful I don't think that we should print out anything (even if we hit errors along the way). I think that only if we end up failing entirely should we print an error. We could certainly explore though a more progress-bar like situation for Cargo where it prints incrementally what it's doing for debugging perhaps?
I think it's sort of encoded as In that sense I wouldn't be too worried about making errors expensive to compute, it hopefully isn't too bad! We can of course profile and test on Servo though to test this out. |
Ok, I think we mostly agree and if we don't it is because we are talking past each other. I think I need to start thinking more "incrementally". I should start with reading the old 'links' code and seeing if I can make the current error messages better. Only then come back to the larger questions of when to print and for witch backtracks. |
c1abbab
to
4ece446
Compare
needs a test where we have an activation_error the then try activate something that dose not work and backtrack to where we had the activation_error then: - Hit fast backtracking that go past the crate with the missing features - Or give a bad error message that does not mention the activation_error. The test will pass, but there is code that is not yet justified by tests
tests/testsuite/features.rs
Outdated
... required by package `foo v0.0.1 ([..])` | ||
versions that meet the requirements `*` are: 0.0.1 | ||
|
||
the package `bar` depends on `bar`, with features: `bar` but it does not have these features. |
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.
Hm shouldn't this read "the package foo" instead of "the package bar"?
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.
Yes, and it is fixed. Thanks. (Sorry about all the force pushing.)
tests/testsuite/features.rs
Outdated
package `bar v0.0.1 ([..])` | ||
... which is depended on by `foo v0.0.1 ([..])` | ||
|
||
all possible versions conflict with previously selected packages. |
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.
Would this clause be possible to remove in this scenario? I think it's more applicable to version conflicts than feature conflicts, 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.
Removed
d0a828d
to
26b96a4
Compare
I think this is finally ready to go. Some things I did not figure out how to test:
|
📌 Commit 2cbd1dd has been approved by |
backtrack if can not activate This is a fix for #4347 Unfortunately this too regressed error messages for the case that you specified a dependency feature that does not exist. @alexcrichton advice on improving the message?
☀️ Test successful - status-appveyor, status-travis |
missed this important bug In the PR #5000 I finished and we merged yesterday I missed a bug and left in an outdated comment. @alexcrichton
Faster resolver: Cache past conflicting_activations, prevent doing the same work repeatedly. This work is inspired by @alexcrichton's [comment](#4066 (comment)) that a slow resolver can be caused by all versions of a dependency being yanked. Witch stuck in my brain as I did not understand why it would happen. If a dependency has no candidates then it will be the most constrained and will trigger backtracking in the next tick. Eventually I found a reproducible test case. If the bad dependency is deep in the tree of dependencies then we activate and backtrack `O(versions^depth)` times. Even tho it is fast to identify the problem that is a lot of work. **The set up:** 1. Every time we backtrack cache the (dep, `conflicting_activations`). 2. Build on the work in #5000, Fail to activate if any of its dependencies will just backtrack to this frame. I.E. for each dependency check if any of its cached `conflicting_activations` are already all activated. If so we can just skip to the next candidate. We also add that bad `conflicting_activations` to our set of `conflicting_activations`, so that we can... **The pay off:** If we fail to find any candidates that we can activate in lite of 2, then we cannot be activated in this context, add our (dep, `conflicting_activations`) to the cache so that next time our parent will not bother trying us. I hear you saying "but the error messages, what about the error messages?" So if we are at the end `!has_another` then we disable this optimization. After we mark our dep as being not activatable then we activate anyway. It won't resolve but it will have the same error message as before this PR. If we have been activated for the error messages then skip straight to the last candidate, as that is the only backtrack that will end with the user. I added a test in the vain of #4834. With the old code the time to run was `O(BRANCHING_FACTOR ^ DEPTH)` and took ~3min with DEPTH = 10; BRANCHING_FACTOR = 5; with the new code it runs almost instantly with 200 and 100.
This is a fix for #4347
Unfortunately this too regressed error messages for the case that you specified a dependency feature that does not exist.
@alexcrichton advice on improving the message?