Do not use non-wf input expectations from fudge when checking function calls#150316
Do not use non-wf input expectations from fudge when checking function calls#150316ShoyuVanilla wants to merge 3 commits intorust-lang:mainfrom
Conversation
| self.param_env, | ||
| ty::ClauseKind::WellFormed(ty.into()), | ||
| )); | ||
| } |
There was a problem hiding this comment.
My intention was to check well-formedness of expected input tys and I thought this would do the thing as they are equated with formal input tys.
But it might be more correct to check them separately outside the fudge
There was a problem hiding this comment.
Kinda related to #150316 (comment), I think this former implementation would be simpler and correct 😅
Yeah, I tried to do two things, checking well-formedness of expected input tys and whether they meet the callee's where bounds 😅 I'll break them into three commits, one for adding tests from related issues, wf check, and where bound check, with blessed test output to visualize the influence of each changes. |
bcc851d to
4b80bc2
Compare
This comment has been minimized.
This comment has been minimized.
4b80bc2 to
443a2f3
Compare
This comment has been minimized.
This comment has been minimized.
|
☔ The latest upstream changes (presumably #151144) made this pull request unmergeable. Please resolve the merge conflicts. |
443a2f3 to
effd66a
Compare
This comment has been minimized.
This comment has been minimized.
|
Sorry for the ping 😅 I've split the changes into multiple commits and blessed tests for each commit. Would this be okay? |
| ocx.try_evaluate_obligations().is_empty() | ||
| }); | ||
| well_formed.then_some(expected_input_tys) | ||
| }); |
There was a problem hiding this comment.
why and then instead of filter?
There was a problem hiding this comment.
Yeah, this is very absurd 😅 I guess I was trying to do more things but just ended up something equivalent to filter
There was a problem hiding this comment.
separete question, why a separate op at all, instead of doing this in the existing and_then above?
There was a problem hiding this comment.
I once considered doing this check inside the fudge scope here but thought that it might make more sense doing wf check outside of the fudge.
If you are meaning doing this after the fudge_inference_if_ok().ok() call, yeah, there's no reason to not to do so 😅
There was a problem hiding this comment.
the second change isn't necessary to avoid any breakage when switching solvers, is it?
I think to fix rust-lang/trait-system-refactor-initiative#259 we should just do f5acf22
I think these sorts of improvements are generally good, but don't like improvements which are only limited to the new solver. I would drop the second commit and then get back to that one once the new solver is stable
|
Yeah, moving generalization outside of the fudge fixes the issue but it regresses back an improvement made by next-solver as said in #t-types/trait-system-refactor > diesel benchmark doesn't compile @ 💬 I'll try combining it with the third commit of this PR and if it doesn't fix the regression, I think this should be closed and revisited once the new solver is stabilized 😄 |
Oops, the third commit + f5acf22 still regresses back |
|
The first change is also old solver, is it not? That one seems cool and I think I'd like to FCP it rn |
|
Oh, I misread your comment 😅 You meant effd66a by the word second commit. Then I'll reopen this with it |
|
Yeah, I understood what you meant by now but I should have written "without it" or "with the first commit" instead of "with it" 😅 Anyway, I'll try that once I get home |
effd66a to
4ef2d8e
Compare
This comment has been minimized.
This comment has been minimized.
|
do you want to also add the move normalize out of fudge to your PR? |
|
more specifically, do you want to integrate https://github.com/lcnr/rust/tree/fudge-norm-outside into your PR? It's annoying to break tests only to unbreak them right afterwards |
|
I think that's good to do so but I can't do it rn because I'm just going out. I'll be back home two or three hours later 😅 |
8ee77f8 to
4cff3dc
Compare
4cff3dc to
8ee77f8
Compare
|
Squashed both commits https://github.com/lcnr/rust/tree/fudge-norm-outside into one and updated tests. |
|
we need to types FCP your wf checking commit here, gonna write that later this week/start of next week |
Let me know if there’s anything I can help with on this |
679a8e4 to
9d9b94b
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
| formal_input_tys | ||
| }; | ||
| // Check the well-formedness of expected input tys, as using ill-formed | ||
| // expectation may cause type inference errors. |
There was a problem hiding this comment.
| // expectation may cause type inference errors. | |
| // expectation may cause type inference errors, see #150316. |
| // If we replace a (unresolved) inference var with a new inference | ||
| // var, it will be eventually resolved to itself and this will | ||
| // weaken type inferences as the new inference var will be fudged | ||
| // out and lose all relationships with other vars while the former | ||
| // will not be fudged. | ||
| if ty.is_ty_var() { | ||
| return ty; | ||
| } |
There was a problem hiding this comment.
is this actually true, especially now that we always resolve things to their root vars, it is unnecessary though :3
There was a problem hiding this comment.
Yeah, this isn't true anymore because of that root var thing + moving generalization out of fudge 😅
9d9b94b to
8bbc91e
Compare
|
@rfcbot fcp merge types |
|
Team member @lcnr has proposed to merge this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
View all comments
cc #149379
r? lcnr
FCP: Do not use non-wf input expectations from fudge when checking function calls
What is fudging?
rust/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Lines 168 to 170 in 71e0027
Consider this coercion site:
let _: Box<dyn Fn(&str) -> usize> = Box::new(|s| s.len());We rely on the expectation to eagerly infer the type of
sto be&str. However,dyn Fn(&str) -> usizeis not a valid type as the argument ofBox::new, as it is notSized.Fudging is the mechanism we use to propagate the expectation through the
Box::newcall without constraining its generic parameter.Fudging computes the expected argument types by acting as if we're able to propagate the expected return type directly through the function, without any coercions on the return site.
Given that we may actually want to coerce afterwards, we cannot actually commit any constraints here. We therefore compute the expectations for the function arguments in a
probeand rely on fudging to be able to name any inference variables created inside of the probe.After the fudging step, we weaken the resulting expectation if it is an unsized type in the following lines:
rust/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Line 354 in 71e0027
rust/compiler/rustc_hir_typeck/src/expectation.rs
Lines 77 to 89 in 71e0027
Because function arguments must be
Sized, this weakening prevents us from applying wrong, unsized coercions to them.How fudging currently goes wrong
We have an opened issue for tracking such cases: #149379.
Broadly, the failures seem to fall into two buckets.
We may end up with non–well-formed expectations
Fudging can produce an expected type that is not well-formed.
That would eventually result in an error failing the well-formedness check, either when we do the coercion with the expected argument types, or when we select the remaining obligations.
Weakening fudged expectation is not covering all the cases
What this PR fixes
One of the problematic cases of the issue
This PR fixes the first case, by simply checking well-formedness of the each expected argument types inside the fudge scope.
This is a reasonable change because:
If fudging fails, we still fall back to using the types from the function signature as expectations in the usual path:
rust/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Lines 330 to 336 in 71e0027
Related tests
Limited for
-Znext-solverSeparately (and not directly tied to the above issue), this PR also fixes a next-solver regression tracked at: rust-lang/trait-system-refactor-initiative#259.
That regression was introduced by #149320, which started normalizing expected function input types inside the fudge scope.
Because all inference-variable relationships and pending obligations are dropped out when we exit the fudge scope, we drop the ambiguous goal used to normalize, leaving us with an unconstrained inference variable in the expectation.
This PR fixes that by normalizing the expectation outside the fudge scope, so the resulting normalization obligations are preserved to the
InferCtxt'sObligationCtxt.Related tests
Does this PR break anything
I don't think there should be any breakage affecting the old solver.
The separate expectation normalization change only affecting the new solver does break an existing test.
This is unfortunate but I think this change should be done because
What this PR doesn't fix
This PR doesn't fix the second case -- Weakening fudged expectation is not covering all the cases.
@lcnr has suggested the following solution for that problem:
I experimented with this and it works well in many cases.
However, on the old solver, checking where-bounds cannot reliably be treated as speculative: if we hit an overflow while checking the where-bounds, the old solver can fail the entire compilation rather than merely treating the check as failed and relaxing the expectation.
Since this second class of issues affects both the old solver and the next-solver, it seems preferable to keep the conservative behavior for now, at least until the next-solver is stabilized, rather than introducing a next-solver-only relaxation that might create new regressions and complicate stabilization efforts.
Related tests