hir_ty_lowering: fix anon const type recovery - #158874
Conversation
|
HIR ty lowering was modified cc @fmease |
|
r? @davidtwco rustbot has assigned @davidtwco. Use Why was this reviewer chosen?The reviewer was selected based on:
|
This comment has been minimized.
This comment has been minimized.
0ce9ac1 to
2b086ad
Compare
This comment has been minimized.
This comment has been minimized.
2b086ad to
7eb6962
Compare
|
@fmease i pushed a much narrower version. i dropped the type-relative recovery path completely, so there is no separate iat/inherent assoc selection anymore. i also removed the generic-arg lowering helper from generics.rs. the remaining type_of code only accepts the exact simple shape from the repro: one resolved segment, one explicit const arg, one own const param, no parent generics, no self, no inferred args, no constraints, no late-bound regions. imo this is aligned with the review feedback while still fixing the bug. there is still a tiny guard in type_of to make sure the anon const maps to that one const param, but idk how to remove even that without either reusing an existing lowering hook or changing the shape of the fix more deeply. ltm if you want zero matching in type_of. in that case i think the next step is finding a proper existing hook, or maybe backing out of this query-side recovery approach. |
This comment has been minimized.
This comment has been minimized.
7eb6962 to
73d0e43
Compare
|
r? compiler |
yeah, fair. my first attempt tried to recover more cases, but after fmease's comments i think that was the wrong direction. it was starting to duplicate too much of generic arg lowering and type-relative/iat selection in but yeah, requiring exactly one generic arg and exactly one own param is probably overcorrecting. i'll keep this limited to direct resolved function paths, but make it handle simple multi-arg cases where this const arg's hir id can be matched to the corresponding own const param without doing real lowering. i'll still bail out for stuff that needs real lowering, like parent generics, self, late-bound regions, constraints, inferred args, defaults, type-relative paths, and const param types that depend on other generics. ltm if that still feels like the wrong place for this. i'm not completely sure, but imo that seems like the least bad middle ground between the first version and this overfit one. |
This comment has been minimized.
This comment has been minimized.
|
Reminder, once the PR becomes ready for a review, use |
|
If there isn’t a strong reason to restrict this to a single generic argument, could you support multiple arguments as well? The current restriction still leaves similar ICEs for valid code such as: fn f<T, const N: u8>() {
f::<u8, { async || {} }>();
} |
Yeah, no strong reason to keep it restricted to one arg, so I lifted that. Pushed in Your exact repro is a regression test now and gives a clean fn f<T, const N: u8>() {
f::<u8, { async || {} }>();
}The recovery matches args positionally against the generic params and only bails when there are more args than can line up, so multiple args just work. btw while I was in there I ran into one more flavor of the same bug: trailing type params with defaults also drop out of the turbofish, so imo positional matching is the right call here. once you drop the exact-count requirement, the omittable-param cases (synthetic verified locally: your repro plus the three existing tests are green, and the whole const-generics anon-const suite passes (840). no rush on my end, nothing asap. (the async-closure-in-a-const trick is a weirdly clean way to trip this race irl, kinda enjoyed chasing it.) |
|
cc @BoxyUwU |
|
@rustbot ready |
Recovering the type from the HIR path meant re-deriving what the generic argument lowering already works out, and only covered the cases the partial classifier recognized: free function paths resolved to `DefKind::Fn`, with no late-bound lifetimes. Anything else still cached an error type and tripped the double-feed ICE, including associated functions, tuple struct constructors, inherent type-relative paths, and const arguments in type annotations, which are not path expressions at all and so cannot be classified this way. With the by-move bodies generated after typeck the anon const's type is always fed before anything asks for it, so drop the recovery along with the tests that only exercised its argument counting. The shapes they covered are folded into the main regression test.
febafdd to
023a327
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. |
|
This makes sense to me 🤔 This is basically just reverting #141950 though I think? @bors try @rust-timer queue though I'm not sure what alternative there is if this is perf sensitive. we can't just move this logic into type checking of closure expressions 🤔 |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…f_race, r=<try> hir_ty_lowering: fix anon const type recovery
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (8d05ea8): comparison URL. Overall result: no relevant changes - no action neededBenchmarking means the PR may be perf-sensitive. Consider adding rollup=never if this change is not fit for rolling up. @rustbot label: -S-waiting-on-perf -perf-regression Instruction countThis perf run didn't have relevant results for this metric. Max RSS (memory usage)Results (primary 5.0%, secondary -5.8%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (secondary 1.4%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeResults (primary 0.1%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Bootstrap: 468.499s -> 468.404s (-0.02%) |
sup, Boxy :) what bites us here is that the loop is parallel. Doing typeck and then the by-move check for one owner doesn't tell us whether its enclosing owner has finished. For the coroutine inside the const arg, I tried fixing it around HIR lowering first, but that turned into chasing each place a const arg can show up, and it duplicated some generic arg matching along the way. Didn't feel like the right layer. Putting the by-move work after body typeck gives us the ordering we need and handles those cases in one place. I don't see a clean way to tie this to closure expression type checking either...the thing we need is for the enclosing body to have already lowered the const arg, and a closure-local hook doesn't give us that ordering. imo the second pass is a little annoying after #141950, but it's also the least surprising fix to me. perf came back with no relevant changes, so I'd keep it like this so far. But if you really want me to change something ltm |
|
Insufficient permissions to issue commands to rust-timer. |
|
@rustbot ready |
|
@bors r+ |
…onst_type_of_race, r=BoxyUwU hir_ty_lowering: fix anon const type recovery fixes rust-lang#158818 `check_crate` used to check whether coroutine closures need a by-move body in the same parallel pass that type-checks body owners. That ordering is the bug. With an async closure inside a const argument, the by-move check asks for `type_of` on the nested coroutine. This can type-check the anon const before the enclosing body lowers the const argument and feeds its expected type. The query caches `{type error}`, then normal lowering later feeds the const parameter's actual type for the same key, so rustc sees two different values and ICEs. I moved the by-move work into a second pass. The first pass gets through normal body type checking and feeds the anon const types. The second pass only starts after that is done, so it cannot ask for the nested coroutine type too early. I think this is a much better place to fix it than the HIR-path recovery I tried earlier. The race starts in `check_crate`, and fixing the ordering there covers path expressions, type positions, and the generic argument cases without keeping a second, incomplete version of generic arg lowering in `type_of`. The UI tests cover the original repro and the nearby shapes that came up while working on it. They run with `-Zthreads=0` and now produce the normal type mismatch instead of an ICE.
…uwer Rollup of 13 pull requests Successful merges: - #158874 (hir_ty_lowering: fix anon const type recovery) - #161443 (add internal DSL for testing binders) - #161617 (Add custom allocators to `(try_)map` on `Box`, `Rc`, `Arc`) - #161726 (Fix debugger visualizer tuple child ordering w/ PDB debug info) - #161729 (miri subtree update) - #161745 (make trivial ABI check resilient against new repr) - #160871 (Remove `#[rustc_reservation_impl]`) - #161180 (Detect missing binding available: add a MaybeIncorrect suggestion) - #161522 (test `f16::mul_add` not double-rounding the result) - #161631 (Add two comments relating to new-solver performance) - #161724 (Add codegen test for static table search loop unrolling) - #161740 (do not compress debuginfo for Cygwin) - #161750 (vector ABI check: reword so it makes more sense for non-obviously-vector types)
Rollup merge of #158874 - Dnreikronos:hir_ty_lowering/anon_const_type_of_race, r=BoxyUwU hir_ty_lowering: fix anon const type recovery fixes #158818 `check_crate` used to check whether coroutine closures need a by-move body in the same parallel pass that type-checks body owners. That ordering is the bug. With an async closure inside a const argument, the by-move check asks for `type_of` on the nested coroutine. This can type-check the anon const before the enclosing body lowers the const argument and feeds its expected type. The query caches `{type error}`, then normal lowering later feeds the const parameter's actual type for the same key, so rustc sees two different values and ICEs. I moved the by-move work into a second pass. The first pass gets through normal body type checking and feeds the anon const types. The second pass only starts after that is done, so it cannot ask for the nested coroutine type too early. I think this is a much better place to fix it than the HIR-path recovery I tried earlier. The race starts in `check_crate`, and fixing the ordering there covers path expressions, type positions, and the generic argument cases without keeping a second, incomplete version of generic arg lowering in `type_of`. The UI tests cover the original repro and the nearby shapes that came up while working on it. They run with `-Zthreads=0` and now produce the normal type mismatch instead of an ICE.
…uwer Rollup of 13 pull requests Successful merges: - rust-lang/rust#158874 (hir_ty_lowering: fix anon const type recovery) - rust-lang/rust#161443 (add internal DSL for testing binders) - rust-lang/rust#161617 (Add custom allocators to `(try_)map` on `Box`, `Rc`, `Arc`) - rust-lang/rust#161726 (Fix debugger visualizer tuple child ordering w/ PDB debug info) - rust-lang/rust#161729 (miri subtree update) - rust-lang/rust#161745 (make trivial ABI check resilient against new repr) - rust-lang/rust#160871 (Remove `#[rustc_reservation_impl]`) - rust-lang/rust#161180 (Detect missing binding available: add a MaybeIncorrect suggestion) - rust-lang/rust#161522 (test `f16::mul_add` not double-rounding the result) - rust-lang/rust#161631 (Add two comments relating to new-solver performance) - rust-lang/rust#161724 (Add codegen test for static table search loop unrolling) - rust-lang/rust#161740 (do not compress debuginfo for Cygwin) - rust-lang/rust#161750 (vector ABI check: reword so it makes more sense for non-obviously-vector types)
…uwer Rollup of 13 pull requests Successful merges: - rust-lang/rust#158874 (hir_ty_lowering: fix anon const type recovery) - rust-lang/rust#161443 (add internal DSL for testing binders) - rust-lang/rust#161617 (Add custom allocators to `(try_)map` on `Box`, `Rc`, `Arc`) - rust-lang/rust#161726 (Fix debugger visualizer tuple child ordering w/ PDB debug info) - rust-lang/rust#161729 (miri subtree update) - rust-lang/rust#161745 (make trivial ABI check resilient against new repr) - rust-lang/rust#160871 (Remove `#[rustc_reservation_impl]`) - rust-lang/rust#161180 (Detect missing binding available: add a MaybeIncorrect suggestion) - rust-lang/rust#161522 (test `f16::mul_add` not double-rounding the result) - rust-lang/rust#161631 (Add two comments relating to new-solver performance) - rust-lang/rust#161724 (Add codegen test for static table search loop unrolling) - rust-lang/rust#161740 (do not compress debuginfo for Cygwin) - rust-lang/rust#161750 (vector ABI check: reword so it makes more sense for non-obviously-vector types)
View all comments
fixes #158818
check_crateused to check whether coroutine closures need a by-move body in the same parallel pass that type-checks body owners.That ordering is the bug. With an async closure inside a const argument, the by-move check asks for
type_ofon the nested coroutine. This can type-check the anon const before the enclosing body lowers the const argument and feeds its expected type. The query caches{type error}, then normal lowering later feeds the const parameter's actual type for the same key, so rustc sees two different values and ICEs.I moved the by-move work into a second pass. The first pass gets through normal body type checking and feeds the anon const types. The second pass only starts after that is done, so it cannot ask for the nested coroutine type too early.
I think this is a much better place to fix it than the HIR-path recovery I tried earlier. The race starts in
check_crate, and fixing the ordering there covers path expressions, type positions, and the generic argument cases without keeping a second, incomplete version of generic arg lowering intype_of.The UI tests cover the original repro and the nearby shapes that came up while working on it. They run with
-Zthreads=0and now produce the normal type mismatch instead of an ICE.