-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Make resolve more perseverant with indeterminate imports. #26242
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
acb101b
to
cec1132
Compare
import_directive.subclass), | ||
help); | ||
self.resolver.resolve_error(span, &msg[..]); | ||
let mut indeterminate = false; |
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.
Instead of a boolean flag, could this just run the push
in the Indeterminate
arm followed by a continue
?
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.
At this point imports
is borrowed by import_directive
, thus I cannot call .swap_remove(..)
. This is why I had to add a scope around the whole match { }
.
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.
But maybe there is a more elegant way to reorder the whole thing, need to think about 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.
Oh right!
cec1132
to
90ee272
Compare
Updated the commit with a cleaner organization than with a boolean flag. And @alexcrichton , I do hope it does not cause any breakage, as it's supposed to make the resolver accept strictly more configurations. 😅 |
I've been pointed on IRC that this might fix #4865 as well, and indeed the last example of the issue compiles fine with my fix. In this case, the issue was that rustc does not resolve imports from a module containing glob imports that have not be resolved ( rust/src/librustc_resolve/resolve_imports.rs Lines 457 to 459 in d7f5fa4
c::*; . With my patch they don't wait any more.
|
Nice! It will be great to get rid of some of these long-standing problems, but we have to be really careful since we're defining new semantics for a notoriously difficult pass. I would feel more confident with more test cases. #4865 has quite a few, and many of them at least look subtly different. Can we add all of them? |
Okay, I've spotted the blocking behavior for the rest of #4865 :
Starting from this, it is obvious how to create a loop and block the algorithm. But I'm afraid the fix for this issue will be far less simple than my current fix (but it is still a different bug, independent of #18083 ). |
@vberger Thanks for the investigation. Can you add the 1 working case still? We should probably have @pcwalton review this since he wrote much of resolve. Maybe @pnkfelix as well. Since this is an important change it should probably be escalated so @rust-lang/lang is aware of it. cc @nrc @nikomatsakis @aturon |
Yeah, this looks OK to me. |
ping @alexcrichton (I think it looks fine to me, btw) |
I'll run this through crater. |
Toolchains are built. Building crates now. |
@vberger do you think this can be fixed, or do the crater fails kill this PR? |
@nrc I'm looking into this, I need to understand why this fails like this before concluding anything. |
Okay, I think I found a minimal example of the breakage: pub use foo::Foo;
use Foo as FooBar;
mod foo {
pub use self::bar::*;
mod bar {
pub struct Foo;
}
} With my PR? this breaks on Apparently, the algorithm considers that, as To make all tihs work, we'll need to make rustc declare imports as "unresolved" less quickly. I think I have an idea about that. |
Okay, this is very troubling. I made this example, which has the same structure as the failing import of Hyper: mod bar {
pub use self::middle::*;
mod middle {
pub use self::baz::Baz;
mod baz {
pub enum Baz {
Baz1,
Baz2
}
}
}
}
mod foo {
use bar::Baz::{Baz1, Baz2};
} But it fails on current nightly, while Hyper compiles... Anyway, overall the resolve algorithm seems to depend on the linear order of resolve (at several points, it decides that if the resolution is indeterminate, then the import must be failed. My above example is an example of one of these cases. If we want to change this, I'll certainly need more thought. Still, I don't give up yet. |
When encountering an indeterminate import, still try to resolve the following imports of the module. This avoids dead-lock-like situations where 2 modules are blocked, each waiting for the resolution of the other. Fixes rust-lang#18083.
66517a6
to
255ce47
Compare
The problem was that some other parts of the algorithm were doing some kind of a "early return", by marking a import as unresolved when it is in fact undeterminate. With the previous ordered approach it was completely valid, as these imports would never have been resolved anyway. It is no longer the case with my change, so I updated them to return This patch successfully passes |
ping @alexcrichton @brson : r? and I guess it'll need an other run of crater ? |
Yeah let's run this through crater again. I believe @brson is on vacation right now, but he can schedule a new run once he's back. |
Started new crater run. |
@bors r+ |
📌 Commit 255ce47 has been approved by |
Awesome work @vberger. Thanks for sticking it out. |
⌛ Testing commit 255ce47 with merge 82865ff... |
💔 Test failed - auto-linux-64-nopt-t |
Hmm, okay. Due to moving the handling of unresolved imports in the main loop, the error messages generated changed (an broke some cfail test). I don't have a lot of time right now, but I'll try to improve during the next days. |
Okay, most of the breakage in the tests is due to several error message changing slightly, for example, both I'm a little more perplex about the On the other hand, other error messages got merged into it, and we probably don't want to lose them: And, last but not least, it appears my assumption about the invariant of the refcell Now, I definitely see what you meant about resolve changes being subtle @alexcrichton 😲 |
☔ The latest upstream changes (presumably #27066) made this pull request unmergeable. Please resolve the merge conflicts. |
@vberger what's your status? |
@gankro I must admit this is getting much more troublesome than I first expected, and I currently don't have a huge lot of time to spend on this. I'll close it for now. I'll create a new PR if I manage to put something up. |
(This is a second try at #26242. This time I think things should be ok.) The current algorithm handling import resolutions works sequentially, handling imports in the order they appear in the source file, and blocking/bailing on the first one generating an error/being unresolved. This can lead to situations where the order of the `use` statements can make the difference between "this code compiles" and "this code fails on an unresolved import" (see #18083 for example). This is especially true when considering glob imports. This PR changes the behaviour of the algorithm to instead try to resolve all imports in a module. If one fails, it is recorded and the next one is tried (instead of directly giving up). Also, all errors generated are stored (and not reported directly). The main loop of the algorithms guaranties that the algorithm will always finish: if a round of resolution does not resolve anything new, we are stuck and give up. At this point, the new version of the algorithm will display all errors generated by the last round of resolve. This way we are sure to not silence relevant errors or help messages, but also to not give up too early. **As a consequence, the import resolution becomes independent of the order in which the `use` statements are written in the source files.** I personally don't see any situations where this could be a problem, but this might need some thought. I passed `rpass` and `cfail` tests on my computer, and now am compiling a full stage2 compiler to ensure the crates reporting errors in my previous attempts still build correctly. I guess once I have checked it, this will need a crater run? Fixes #18083. r? @alexcrichton , cc @nrc @brson
This changes the behavior of the resolver from giving up at the first indeterminate import to trying to resolve everything in the current module.
It should make the resolving independent of the order in which the
use
statements are written in the source file (which is not the case currently).I am currently running
make check-stage1
on my computer, takes quite a long time, but no error yet. I still tested manually the example from #18083.Fixes #18083.