traits: Fix rigid alias liveness matching - #160212
Dnreikronos wants to merge 1 commit into
Conversation
|
r? @JohnTitor rustbot has assigned @JohnTitor. Use Why was this reviewer chosen?The reviewer was selected based on:
|
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
I'm not sure this is correct. Or, at least, I'm not sure this is the right fix. It certainly isn't principled.
I don't have time to fully dig in right now, but generally I would not expect us to arbitrarily be setting things as rigid. I'm not sure the correct fix, but the may even be in the use or definition of extract_verify_if_eq (or may not be).
|
Yeah, that makes sense. I reworked this so liveness does not set aliases rigid anymore. The ICE was in the path you pointed at, or at least right next to it: So imo the better fix is to make btw I kept the liveness-side identity alias as |
|
We previously have a |
|
@adwinwhite can you review here? You're much more familiar with what might be the correct fix here than I am. |
|
r? me |
|
Thanks! Ping me if there's a question here for me or something otherwise needed from me! |
|
I think we shouldn't weaken the checks in The reasons we have non-rigid aliases here are
It's difficult to normalize here. So we have to live with a hack, hopefully less bad :/ |
This comment has been minimized.
This comment has been minimized.
|
I would very much not like to land a hack here; I'd like to stay principled in this space, because the soundness around opaque type liveness involves accurately identifying regions that could be within an alias. This is a query because:
The only thing that I worry about is something like |
|
Wassup, ty both for your time invested! Two things I hit while working through @adwinwhite's plan that I want to confirm first, because I don't think it and @jackh726's "no hack" constraint fully agree yet. The filtering I'll just do. The clause that ICEs comes from Question 1: making Question 2: the assert in The alternative I'd rather write: everything the query and imo the index version is worth the churn even though it's the bigger diff. Every time we launder rigidness through an One more, @jackh726, on |
a9ef45e to
5c1eddb
Compare
This comment has been minimized.
This comment has been minimized.
|
These commits modify the If this was unintentional then you should revert the changes before this PR is merged. |
|
@lcnr update: I pulled the bitset work out into #160936 so this PR stays focused on the behavioral / Zulip context still applies: https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/rigid.20aliases.20in.20region.20handling/near/615557841 imo the bitset was the right first step, but mixing it here made the review surface noisier than it needed to be. the open question on this PR is still the matcher: do we need proper matching/normalization in fyi I left the ignore-rigidness matcher commit here for now. lmk if you'd rather I drop it / swap to the exact- |
This comment has been minimized.
This comment has been minimized.
|
can you split out the bitset change from the behaviorial changes in this PR? ideally open a separate PR for just the bitset change |
Ofc! |
3d4d472 to
db4cb2b
Compare
This comment has been minimized.
This comment has been minimized.
|
@lcnr split's done. Bitset landed in #160936. This PR is back to just the behavioral / imo that's cleaner for review. the bitset is pure churn on query shape, and mixing it with the ICE fix was making the diff harder to reason about than it needed to be. lmk if you'd rather I stack #160212 on top of that one instead of keeping them independent. |
…t, r=lcnr,jackh726,adwinwhite traits: Represent live alias arguments as bitsets Split out of rust-lang#160212 per review / Zulip: https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/rigid.20aliases.20in.20region.20handling/near/615557841 `live_args_for_alias_from_outlives_bounds` and `args_known_to_outlive_alias_params` now return identity arg indices (`DenseBitSet`) instead of `EarlyBinder<GenericArg>`. Callers just do `args[idx].visit_with(...)`, so we stop laundering rigidness through binder instantiate. Also drops the old BitSet FIXME. imo this is worth doing on its own even without the ICE fix. every time we shoved identity params through `EarlyBinder` we were writing down something we don't actually know, and this module is only going to grow. better to make the invariant explicit now than keep paying for it later. No behavioral change intended. the rigid-alias ICE / `extract_verify_if_eq` bits stay on rust-lang#160212. btw if that one should stack on this instead of staying independent, lmk and I'll rebase it asap.
…t, r=lcnr,jackh726,adwinwhite traits: Represent live alias arguments as bitsets Split out of rust-lang#160212 per review / Zulip: https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/rigid.20aliases.20in.20region.20handling/near/615557841 `live_args_for_alias_from_outlives_bounds` and `args_known_to_outlive_alias_params` now return identity arg indices (`DenseBitSet`) instead of `EarlyBinder<GenericArg>`. Callers just do `args[idx].visit_with(...)`, so we stop laundering rigidness through binder instantiate. Also drops the old BitSet FIXME. imo this is worth doing on its own even without the ICE fix. every time we shoved identity params through `EarlyBinder` we were writing down something we don't actually know, and this module is only going to grow. better to make the invariant explicit now than keep paying for it later. No behavioral change intended. the rigid-alias ICE / `extract_verify_if_eq` bits stay on rust-lang#160212. btw if that one should stack on this instead of staying independent, lmk and I'll rebase it asap.
…t, r=lcnr,jackh726,adwinwhite traits: Represent live alias arguments as bitsets Split out of rust-lang#160212 per review / Zulip: https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/rigid.20aliases.20in.20region.20handling/near/615557841 `live_args_for_alias_from_outlives_bounds` and `args_known_to_outlive_alias_params` now return identity arg indices (`DenseBitSet`) instead of `EarlyBinder<GenericArg>`. Callers just do `args[idx].visit_with(...)`, so we stop laundering rigidness through binder instantiate. Also drops the old BitSet FIXME. imo this is worth doing on its own even without the ICE fix. every time we shoved identity params through `EarlyBinder` we were writing down something we don't actually know, and this module is only going to grow. better to make the invariant explicit now than keep paying for it later. No behavioral change intended. the rigid-alias ICE / `extract_verify_if_eq` bits stay on rust-lang#160212. btw if that one should stack on this instead of staying independent, lmk and I'll rebase it asap.
…t, r=lcnr,jackh726,adwinwhite traits: Represent live alias arguments as bitsets Split out of rust-lang#160212 per review / Zulip: https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/rigid.20aliases.20in.20region.20handling/near/615557841 `live_args_for_alias_from_outlives_bounds` and `args_known_to_outlive_alias_params` now return identity arg indices (`DenseBitSet`) instead of `EarlyBinder<GenericArg>`. Callers just do `args[idx].visit_with(...)`, so we stop laundering rigidness through binder instantiate. Also drops the old BitSet FIXME. imo this is worth doing on its own even without the ICE fix. every time we shoved identity params through `EarlyBinder` we were writing down something we don't actually know, and this module is only going to grow. better to make the invariant explicit now than keep paying for it later. No behavioral change intended. the rigid-alias ICE / `extract_verify_if_eq` bits stay on rust-lang#160212. btw if that one should stack on this instead of staying independent, lmk and I'll rebase it asap.
…t, r=lcnr,jackh726,adwinwhite traits: Represent live alias arguments as bitsets Split out of rust-lang#160212 per review / Zulip: https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/rigid.20aliases.20in.20region.20handling/near/615557841 `live_args_for_alias_from_outlives_bounds` and `args_known_to_outlive_alias_params` now return identity arg indices (`DenseBitSet`) instead of `EarlyBinder<GenericArg>`. Callers just do `args[idx].visit_with(...)`, so we stop laundering rigidness through binder instantiate. Also drops the old BitSet FIXME. imo this is worth doing on its own even without the ICE fix. every time we shoved identity params through `EarlyBinder` we were writing down something we don't actually know, and this module is only going to grow. better to make the invariant explicit now than keep paying for it later. No behavioral change intended. the rigid-alias ICE / `extract_verify_if_eq` bits stay on rust-lang#160212. btw if that one should stack on this instead of staying independent, lmk and I'll rebase it asap.
…t, r=lcnr,jackh726,adwinwhite traits: Represent live alias arguments as bitsets Split out of rust-lang#160212 per review / Zulip: https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/rigid.20aliases.20in.20region.20handling/near/615557841 `live_args_for_alias_from_outlives_bounds` and `args_known_to_outlive_alias_params` now return identity arg indices (`DenseBitSet`) instead of `EarlyBinder<GenericArg>`. Callers just do `args[idx].visit_with(...)`, so we stop laundering rigidness through binder instantiate. Also drops the old BitSet FIXME. imo this is worth doing on its own even without the ICE fix. every time we shoved identity params through `EarlyBinder` we were writing down something we don't actually know, and this module is only going to grow. better to make the invariant explicit now than keep paying for it later. No behavioral change intended. the rigid-alias ICE / `extract_verify_if_eq` bits stay on rust-lang#160212. btw if that one should stack on this instead of staying independent, lmk and I'll rebase it asap.
Rollup merge of #160936 - Dnreikronos:traits/live_args_bitset, r=lcnr,jackh726,adwinwhite traits: Represent live alias arguments as bitsets Split out of #160212 per review / Zulip: https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/rigid.20aliases.20in.20region.20handling/near/615557841 `live_args_for_alias_from_outlives_bounds` and `args_known_to_outlive_alias_params` now return identity arg indices (`DenseBitSet`) instead of `EarlyBinder<GenericArg>`. Callers just do `args[idx].visit_with(...)`, so we stop laundering rigidness through binder instantiate. Also drops the old BitSet FIXME. imo this is worth doing on its own even without the ICE fix. every time we shoved identity params through `EarlyBinder` we were writing down something we don't actually know, and this module is only going to grow. better to make the invariant explicit now than keep paying for it later. No behavioral change intended. the rigid-alias ICE / `extract_verify_if_eq` bits stay on #160212. btw if that one should stack on this instead of staying independent, lmk and I'll rebase it asap.
…,jackh726,adwinwhite traits: Represent live alias arguments as bitsets Split out of rust-lang/rust#160212 per review / Zulip: https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/rigid.20aliases.20in.20region.20handling/near/615557841 `live_args_for_alias_from_outlives_bounds` and `args_known_to_outlive_alias_params` now return identity arg indices (`DenseBitSet`) instead of `EarlyBinder<GenericArg>`. Callers just do `args[idx].visit_with(...)`, so we stop laundering rigidness through binder instantiate. Also drops the old BitSet FIXME. imo this is worth doing on its own even without the ICE fix. every time we shoved identity params through `EarlyBinder` we were writing down something we don't actually know, and this module is only going to grow. better to make the invariant explicit now than keep paying for it later. No behavioral change intended. the rigid-alias ICE / `extract_verify_if_eq` bits stay on rust-lang/rust#160212. btw if that one should stack on this instead of staying independent, lmk and I'll rebase it asap.
…,jackh726,adwinwhite traits: Represent live alias arguments as bitsets Split out of rust-lang/rust#160212 per review / Zulip: https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/rigid.20aliases.20in.20region.20handling/near/615557841 `live_args_for_alias_from_outlives_bounds` and `args_known_to_outlive_alias_params` now return identity arg indices (`DenseBitSet`) instead of `EarlyBinder<GenericArg>`. Callers just do `args[idx].visit_with(...)`, so we stop laundering rigidness through binder instantiate. Also drops the old BitSet FIXME. imo this is worth doing on its own even without the ICE fix. every time we shoved identity params through `EarlyBinder` we were writing down something we don't actually know, and this module is only going to grow. better to make the invariant explicit now than keep paying for it later. No behavioral change intended. the rigid-alias ICE / `extract_verify_if_eq` bits stay on rust-lang/rust#160212. btw if that one should stack on this instead of staying independent, lmk and I'll rebase it asap.
db4cb2b to
97b5b5a
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. |
|
@rustbot author |
|
Reminder, once the PR becomes ready for a review, use |
Item bounds already instantiate higher-ranked GAT arguments with identity parameters. Compare the bound self type with the identity alias directly, and treat any remaining bound region as static.
97b5b5a to
fb554f2
Compare
|
@rustbot ready |
|
@bors r+ rollup |
…eness, r=adwinwhite traits: Fix rigid alias liveness matching Fixes rust-lang#160206 The ICE happens while borrowck computes liveness for an opaque return type with an associated type bound. In the repro, that bound looks like `<impl Foo<'x> as Foo<'x>>::Out: 'static`. The query passes unnormalized item bounds to `extract_verify_if_eq`, which expects rigid aliases with the next solver, and hits its debug assertion. Item-bound collection already maps higher-ranked GAT arguments to the GAT's identity parameters. That means this query can compare the bound's self type directly with the identity alias. A bound on a nested projection, like the associated type in the repro, doesn't match the opaque itself and gets skipped. It doesn't tell us that the opaque is `'static`. For bounds that do match, we keep the outlives region unless it's still bound. For example, `for<'b> Self::Assoc<'b>: 'b` becomes a non higher ranker item bound `Self::Assoc<'param>: 'param`, so that param region still matters for liveness. With `for<'b> Self::Assoc: 'b`, the same associated type has to outlive every choice of `'b`, including `'static`. We handle that case directly. I think this is a better fit for the query because it uses the work item-bound collection already did. It removes the matcher call from this path and keeps the shared matcher's rigidity checks intact. The separate call for function bounds stays, since it still needs to match against the alias's concrete arguments. There's no extra normalization in liveness. The original repro covers the case that triggered the assertion: an item bound on a nested projection must be skipped when computing liveness for the opaque itself.
Rollup of 12 pull requests Successful merges: - #161596 (coretests: Add more pattern tests.) - #162796 (libtest: do not early exit from test runners) - #162844 (Add loan reachability traces to polonius MIR dumps) - #158186 (Guarantee 8 bytes of alignment of RawWakerVTable) - #160108 (Stabilize `windows_process_extensions_main_thread_handle`) - #160212 (traits: Fix rigid alias liveness matching) - #160544 (Stabilize `feature(trim_prefix_suffix)` (`{str, [T], Path}::trim_prefix` and `{str, [T]}::trim_suffix`)) - #161305 (Use the entire type of a dropped local to compute variance (edge direction) for Polonius alpha) - #161838 (tests: accept LLVM 24 optimization in this test) - #162805 (Add `must_use` lint to `ExitCode`) - #162825 (core: Add examples for `debug_closure_helpers`) - #162856 (Stabilize CommandExt::show_window)
…eness, r=adwinwhite traits: Fix rigid alias liveness matching Fixes rust-lang#160206 The ICE happens while borrowck computes liveness for an opaque return type with an associated type bound. In the repro, that bound looks like `<impl Foo<'x> as Foo<'x>>::Out: 'static`. The query passes unnormalized item bounds to `extract_verify_if_eq`, which expects rigid aliases with the next solver, and hits its debug assertion. Item-bound collection already maps higher-ranked GAT arguments to the GAT's identity parameters. That means this query can compare the bound's self type directly with the identity alias. A bound on a nested projection, like the associated type in the repro, doesn't match the opaque itself and gets skipped. It doesn't tell us that the opaque is `'static`. For bounds that do match, we keep the outlives region unless it's still bound. For example, `for<'b> Self::Assoc<'b>: 'b` becomes a non higher ranker item bound `Self::Assoc<'param>: 'param`, so that param region still matters for liveness. With `for<'b> Self::Assoc: 'b`, the same associated type has to outlive every choice of `'b`, including `'static`. We handle that case directly. I think this is a better fit for the query because it uses the work item-bound collection already did. It removes the matcher call from this path and keeps the shared matcher's rigidity checks intact. The separate call for function bounds stays, since it still needs to match against the alias's concrete arguments. There's no extra normalization in liveness. The original repro covers the case that triggered the assertion: an item bound on a nested projection must be skipped when computing liveness for the opaque itself.
View all comments
Fixes #160206
The ICE happens while borrowck computes liveness for an opaque return type with an associated type bound. In the repro, that bound looks like
<impl Foo<'x> as Foo<'x>>::Out: 'static. The query passes unnormalized item bounds toextract_verify_if_eq, which expects rigid aliases with the next solver, and hits its debug assertion.Item-bound collection already maps higher-ranked GAT arguments to the GAT's identity parameters. That means this query can compare the bound's self type directly with the identity alias. A bound on a nested projection, like the associated type in the repro, doesn't match the opaque itself and gets skipped. It doesn't tell us that the opaque is
'static.For bounds that do match, we keep the outlives region unless it's still bound. For example,
for<'b> Self::Assoc<'b>: 'bbecomes a non higher ranker item boundSelf::Assoc<'param>: 'param, so that param region still matters for liveness. Withfor<'b> Self::Assoc: 'b, the same associated type has to outlive every choice of'b, including'static. We handle that case directly.I think this is a better fit for the query because it uses the work item-bound collection already did. It removes the matcher call from this path and keeps the shared matcher's rigidity checks intact. The separate call for function bounds stays, since it still needs to match against the alias's concrete arguments. There's no extra normalization in liveness.
The original repro covers the case that triggered the assertion: an item bound on a nested projection must be skipped when computing liveness for the opaque itself.