Fix vtable ICE on unsatisfied supertrait bounds#154129
Fix vtable ICE on unsatisfied supertrait bounds#154129cdown wants to merge 1 commit intorust-lang:mainfrom
Conversation
|
r? @mati865 rustbot has assigned @mati865. Use Why was this reviewer chosen?The reviewer was selected based on:
|
This comment has been minimized.
This comment has been minimized.
6e6d9f7 to
e35a678
Compare
|
r? @lcnr |
This comment has been minimized.
This comment has been minimized.
|
^ that's because we happen to have different resolution ordering after this change. but it's the test that needs adjusting really, it shouldn't care which method it hits, only that it should hit the type length limit |
e35a678 to
114961e
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. |
| @@ -1,4 +1,4 @@ | |||
| //~ ERROR reached the type-length limit | |||
| //~? ERROR reached the type-length limit | |||
There was a problem hiding this comment.
this is because of the change in ordering.
| = note: consider using `--verbose` to print the full type name to the console | ||
|
|
||
| error: reached the type-length limit while instantiating `<{closure@...} as FnMut<()>>::call_mut` | ||
| error: reached the type-length limit while instantiating `<{closure@...} as FnOnce<()>>::call_once` |
There was a problem hiding this comment.
this is also because of the change in ordering.
114961e to
998ce6b
Compare
This comment has been minimized.
This comment has been minimized.
998ce6b to
ed879e6
Compare
|
Please also test this code from #154073 (comment) trait Bar: Sync {
fn method(&self);
}
impl<T: Sync> Bar for T {
// missing method
}
static BAR: &dyn Sync = &false as &dyn Bar;
fn main(){} |
ed879e6 to
af0e626
Compare
|
Thanks, added. |
When a trait impl doesn't satisfy its supertrait bounds (for example, `impl<T: Send> Bar for T` where `trait Bar: Droppable` but `T` has no `Droppable` bound), the compiler emits E0277 and then then continues compilation. If a static initialiser then upcasts through this broken impl, const evaluation builds the vtable and tries to resolve methods for the unsatisfied supertrait (for example, `<bool as Droppable>::drop`). One might think that the `impossible_predicates` guard in `vtable_entries` should catch this, but it doesn't, because it calls `predicates_of(method).instantiate_own()`, which only includes the method's own where clauses, and the parent trait's `Self: Trait` predicate lives on the trait definition, not the method, so the guard passes and we fall through to `expect_resolve_for_vtable`, which hits a `span_bug!` when resolution returns `Ok(None)`. There was a previous attempt to fix this in issue 152287, which worked by switching to `instantiate_and_check_impossible_predicates`, which includes parent predicates and the trait ref. But unfortunately this is unsound and was reverted because `impossible_predicates` has a pre-existing unsoundness with coroutine witness types and opaque types (see issue 153596). Let's take a different approach that avoids `impossible_predicates` entirely. Let's extract the core of `expect_resolve_for_vtable` into a fallible `try_resolve_for_vtable` that returns `Result<Instance, ErrorGuaranteed>`, and on resolution failure emit a `delayed_bug`. `vtable_entries` then can use this and return `VtblEntry::Vacant` on the error path.
af0e626 to
dd711dd
Compare
When a trait impl doesn't satisfy its supertrait bounds (for example,
impl<T: Send> Bar for Twheretrait Bar: DroppablebutThas noDroppablebound), the compiler emits E0277 and then then continues compilation.If a static initialiser then upcasts through this broken impl, const evaluation builds the vtable and tries to resolve methods for the unsatisfied supertrait (for example,
<bool as Droppable>::drop).One might think that the
impossible_predicatesguard invtable_entriesshould catch this, but it doesn't, because it callspredicates_of(method).instantiate_own(), which only includes the method's own where clauses, and the parent trait'sSelf: Traitpredicate lives on the trait definition, not the method, so the guard passes and we fall through toexpect_resolve_for_vtable, which hits aspan_bug!when resolution returnsOk(None).There was a previous attempt to fix this in #152287, which worked by switching to
instantiate_and_check_impossible_predicates, which includes parent predicates and the trait ref. But unfortunately this is unsound and was reverted becauseimpossible_predicateshas a pre-existing unsoundness with coroutine witness types and opaque types (see #153596).Let's take a different approach that avoids
impossible_predicatesentirely. Let's extract the core ofexpect_resolve_for_vtableinto a fallibletry_resolve_for_vtablethat returnsResult<Instance, ErrorGuaranteed>, and on resolution failure emit adelayed_bug.vtable_entriesthen can use this and returnVtblEntry::Vacanton the error path.Fixes #154073, #137190