delay unexpected successful goal during ambiguity reporting - #162182
Conversation
|
Some changes occurred to the core trait solver cc @rust-lang/initiative-trait-system-refactor |
|
r? @nnethercote rustbot has assigned @nnethercote. Use Why was this reviewer chosen?The reviewer was selected based on:
|
|
It should be a bigger problem if we can have stale stalled-on? 🤔 |
I don’t think this necessarily means the normal goal_remains_stalled path is broken the fix here is to stop treating pending obligations there and reevaluate the drained obligation without cached stalled_on |
f907e8d to
8043aee
Compare
|
I will pass this on to someone who knows more about this stuff than I do. r? @adwinwhite |
But I guess using |
by stale I mean stale at the final error collection point the obligation is still in the pending list but when It only rechecks drained pending obligations at the diagnostics boundary instead of blindly turning all of them into Ambiguity |
|
I mean, what makes them stale at the final error collection point? If the goal is stalled on some conditions, e.g. some vars or opaque types and those conditions still remain unchanged, what could make goal evaluation successful then? I'm not denying what's actually happening. What I want to say is it would be better to dig into the root cause rather than fixing the surfaced ICE directly |
|
What I know right now is only the symptom The real thing to check is whether |
|
for the obligations that fresh evaluate to Yes during final collection the cached stalled_on had no concrete wake-up dependency: goal_remains_stalled(stalled_on) still returned true and fulfillment skipped re-evaluating them but evaluating the same goal without the cached stalled_on returned Yes I tested moving the fix earlier by not reusing stalled_on when it records no concrete dependency. with the final collection filtering removed the original repro no longer ICEs and only reports the normal diagnostics I think the right fix is to make this a stalled cache issue instead of handling it only in collect_remaining_errors_impl. does that direction sound right? |
|
Hmm, I think the most problematic thing is that we are getting an empty I guess the following is the relevant lines that allegedly builds an empty rust/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs Lines 819 to 881 in 71238e2 So, to build an empty But what really happens doesn't match with this. So I guess there are some possibilities like..
|
|
I checked the two possibilities you mentioned the more suspicious part is those all go through the lifetime arm and are not tracked and the goal is not actually boring after canonicalization. it still depends on region state but that state is not represented in the cached stalled_on |
|
Interesting. So maybe the lifetimes are actually making the goal stalled in this case, unlike our comment 🤔 |
8043aee to
9f387d0
Compare
|
I tried the broader version first but it turned out to be too aggressive. it also affected coroutine-stalled goals. the current one keeps cached stalled states when |
|
I looked into this a bit and I found the actual problem. // Edition >= 2021
trait MyTrait {}
impl MyTrait for () {}
impl<'de> DeserTrait<'de> for &'de DeserStruct {}
trait DeserTrait<'de> {}
struct DeserStruct;
impl DeserTrait<'_> for &'static MyTrait {}
fn test() -> impl Send {
testfn(&DeserStruct)
}
fn testfn<'de, D: DeserTrait<'de>>(_deserializer: D) -> impl MyTrait + 'static {}
fn main() {}So this is your test code that ICEs. To prove Normally, this should be proved via the implementation But we have malformed another impl And this becomes another candidate as we equate the args for the trait goal and the impl candidates to check whether it's a candidate and the error type can be equated with any type: rust/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs Lines 60 to 125 in b924f94 rust/compiler/rustc_type_ir/src/relate/combine.rs Lines 51 to 55 in b924f94 So, this becomes another candidates with region constraint Thus, candidates are:
The certainties of these candidates are all rust/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs Lines 1616 to 1620 in b924f94 And as you've found out, all the args in this goals are lifetimes, so we get an empty But during typeck, we end up erase So, when we finish the typeck collecting the errors the same stalled goal have the previous two candidates:
But this time, as
And
This suddenly makes candidate merging return an always applicable candidate instead of ambiguity rust/compiler/rustc_next_trait_solver/src/solve/mod.rs Lines 306 to 320 in b924f94 And this is why this ICE happens |
|
So, what should we do? I think we shouldn't consider I think we shouldn't ignore the empty I think we simply emit delayed bugs in the very line currently emits ICEs as there must be other error and if not it will be a real bug. Or even better, we can do so only if the current |
|
Thanks that explains the state transition I was missing. I updated the patch to avoid fixing this as a Instead of dropping the error-type impl candidate the new version keeps it available for diagnostics but disables the always applicable merge fast path when any impl candidate header references an error type |
375c519 to
1c6c74b
Compare
|
gonna pass the review to @ShoyuVanilla for obvious reasons :> |
There was a problem hiding this comment.
Yeah, I felt a bit worried about the second commit 1c6c74b bc the problematic situation is the opposite direction, i.e. the erronous candidate makes the candidate select flounder. And it might worsen the rust-analyzer's type inference as it oftentimes has candidates contains error type/region/consts due to some implementation flaws/limitations. I think alternatively, we could drop erronous candidates from for_each_relevant_impl's implementation in the rustc_middle side
Could you squash the commits and change the PR and commit title accordingly?
751f2b3 to
01f2eb7
Compare
|
One thing I think is worth checking. that seems a little different from your earlier point that there should already be another error here otherwise it should stay a real bug I tried set guard on Would |
Yeah, fair point. I was thinking of emitting a delayed bug and then emitting no fulfillment error for that obligation, so that having no other error would end up triggering the ICE eventually but yeah, missed that while reviewing the actual code 😅 |
01f2eb7 to
7f63341
Compare
There was a problem hiding this comment.
I think the test file name should be changed as it's not actually about stale stalled.
And could you remove the issue number from the filename and add a comment like // Regression test for <https://github.com/rust-lang/rust/issues/161669> instead?
| Self: Sized, | ||
| { | ||
| Some(Self::from_solver_error(infcx, error)) | ||
| } |
There was a problem hiding this comment.
This feels a bit awkward as this is only used for collect_remaining_errors in next-solver.
Yeah, it's a pain that current API forces us to handle solver error as a real fulfillment error 🤔
How about moving evaluating the pending obligations and filtering for delayed bug here
, make NextSolverError::Ambiguity carry extra fields for error mapping and comment why we need this?
That would be still ugly but I guess that might be less puzzling
| } else { | ||
| TraitErrors::HasErrors(collect_remaining_errors_impl(self, infcx)) | ||
| let errors = collect_remaining_errors_impl(self, infcx); | ||
| TraitErrors::from_iter(errors.into_iter()) |
Signed-off-by: Amirhossein Akhlaghpour <m9.akhlaghpoor@gmail.com> refactor next solver ambiguity error reporting Signed-off-by: Amirhossein Akhlaghpour <m9.akhlaghpoor@gmail.com>
9f73b4c to
d742397
Compare
Rollup of 14 pull requests Successful merges: - #162404 (`rust-analyzer` subtree update) - #161624 (diagnostics: Point closure trait errors at captured values) - #161697 (make `Complex` ABI-compatible on sparc64 and powerpc64) - #162182 (delay unexpected successful goal during ambiguity reporting) - #162328 (Allow overriding filecheck even if LLVM is built or downloaded) - #162367 (Use `reason` for tracked item diagnostics from `cfg_select!`) - #162381 (fix bare urls split text) - #162388 (std: fix set_permissions_nofollow on espidf and horizon) - #162319 (docs(core): correct ARMv8-M Baseline atomic CAS support) - #162341 (add regression test for packus_epi16 issue) - #162383 (Add a hint for using `nolimit` to the limiting error message) - #162384 (remove EnumSizeOpt) - #162390 (remove outdated comment in `UnsafeCell::raw_get` source) - #162397 (docs: Ask for ABI documentation in the platform support template)
Rollup merge of #162182 - amirHdev:skip-stale-stalled-obligations, r=ShoyuVanilla delay unexpected successful goal during ambiguity reporting fixes #161669 During final ambiguity reporting a stalled obligation can unexpectedly reevaluate successfully after an earlier compilation error Instead of immediately ICEing when this happens emit a delayed compiler bug and continue reporting the ambiguity
View all comments
fixes #161669
During final ambiguity reporting a stalled obligation can unexpectedly reevaluate successfully after an earlier compilation error
Instead of immediately ICEing when this happens emit a delayed compiler bug and continue reporting the ambiguity