Fix ICE in next-solver dyn-compatibility check

The next solver treated error-containing dispatchability goals as proven and misclassified the trait as dyn compatible. Short-circuit receivers with type errors so object-method confirmation stays on the normal error path.
This commit is contained in:
cijiugechu
2026-04-07 22:55:42 +08:00
parent 906ca7ff5e
commit 89a4742773
3 changed files with 92 additions and 0 deletions
@@ -603,6 +603,9 @@ fn receiver_for_self_ty<'tcx>(
/// contained by the trait object, because the object that needs to be coerced is behind
/// a pointer.
///
/// If lowering already produced an error in the receiver type, we conservatively treat it as
/// undispatchable instead of asking the solver.
///
/// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result in
/// a new check that `Trait` is dyn-compatible, creating a cycle.
/// Instead, we emulate a placeholder by introducing a new type parameter `U` such that
@@ -630,6 +633,10 @@ fn receiver_is_dispatchable<'tcx>(
) -> bool {
debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
if receiver_ty.references_error() {
return false;
}
let (Some(unsize_did), Some(dispatch_from_dyn_did)) =
(tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait())
else {
@@ -0,0 +1,23 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/151311>
//@ edition: 2024
//@ compile-flags: -Znext-solver=globally
#![feature(unsafe_binders)]
use std::ops::Deref;
trait Foo: Deref<Target = unsafe<'a> &'a dyn Bar> {
fn method(self: &unsafe<'ops> &'a Bar) {}
//~^ ERROR expected a type, found a trait
//~| ERROR use of undeclared lifetime name `'a`
}
trait Bar {}
fn test(x: &dyn Foo) {
//~^ ERROR the trait `Foo` is not dyn compatible
x.method();
//~^ ERROR no method named `method` found for reference `&dyn Foo`
}
fn main() {}
@@ -0,0 +1,62 @@
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:10:36
|
LL | fn method(self: &unsafe<'ops> &'a Bar) {}
| ^^ undeclared lifetime
|
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
help: consider making the type lifetime-generic with a new `'a` lifetime
|
LL | fn method(self: &unsafe<'a, 'ops> &'a Bar) {}
| +++
help: consider introducing lifetime `'a` here
|
LL | fn method<'a>(self: &unsafe<'ops> &'a Bar) {}
| ++++
help: consider introducing lifetime `'a` here
|
LL | trait Foo<'a>: Deref<Target = unsafe<'a> &'a dyn Bar> {
| ++++
error[E0782]: expected a type, found a trait
--> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:10:39
|
LL | fn method(self: &unsafe<'ops> &'a Bar) {}
| ^^^
|
help: you can add the `dyn` keyword if you want a trait object
|
LL | fn method(self: &unsafe<'ops> &'a dyn Bar) {}
| +++
error[E0038]: the trait `Foo` is not dyn compatible
--> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:17:13
|
LL | fn method(self: &unsafe<'ops> &'a Bar) {}
| --------------------- help: consider changing method `method`'s `self` parameter to be `&self`: `&Self`
...
LL | fn test(x: &dyn Foo) {
| ^^^^^^^ `Foo` is not dyn compatible
|
note: for a trait to be dyn compatible it needs to allow building a vtable
for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:10:21
|
LL | trait Foo: Deref<Target = unsafe<'a> &'a dyn Bar> {
| --- this trait is not dyn compatible...
LL | fn method(self: &unsafe<'ops> &'a Bar) {}
| ^^^^^^^^^^^^^^^^^^^^^ ...because method `method`'s `self` parameter cannot be dispatched on
error[E0599]: no method named `method` found for reference `&dyn Foo` in the current scope
--> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:19:7
|
LL | fn method(self: &unsafe<'ops> &'a Bar) {}
| --------------------- the method might not be found because of this arbitrary self type
...
LL | x.method();
| ^^^^^^ method not found in `&dyn Foo`
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0038, E0261, E0599, E0782.
For more information about an error, try `rustc --explain E0038`.