From 89a4742773beb36a52ce4876aadb151e0fc5b8e1 Mon Sep 17 00:00:00 2001 From: cijiugechu Date: Tue, 7 Apr 2026 22:55:42 +0800 Subject: [PATCH] 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. --- .../src/traits/dyn_compatibility.rs | 7 +++ ...e-binders-bare-trait-object-next-solver.rs | 23 +++++++ ...nders-bare-trait-object-next-solver.stderr | 62 +++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 tests/ui/dyn-compatibility/unsafe-binders-bare-trait-object-next-solver.rs create mode 100644 tests/ui/dyn-compatibility/unsafe-binders-bare-trait-object-next-solver.stderr diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index f1ab59abc6ae..b70b05970f26 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -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 { diff --git a/tests/ui/dyn-compatibility/unsafe-binders-bare-trait-object-next-solver.rs b/tests/ui/dyn-compatibility/unsafe-binders-bare-trait-object-next-solver.rs new file mode 100644 index 000000000000..27bf1d149415 --- /dev/null +++ b/tests/ui/dyn-compatibility/unsafe-binders-bare-trait-object-next-solver.rs @@ -0,0 +1,23 @@ +//! Regression test for +//@ edition: 2024 +//@ compile-flags: -Znext-solver=globally + +#![feature(unsafe_binders)] + +use std::ops::Deref; + +trait Foo: Deref &'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() {} diff --git a/tests/ui/dyn-compatibility/unsafe-binders-bare-trait-object-next-solver.stderr b/tests/ui/dyn-compatibility/unsafe-binders-bare-trait-object-next-solver.stderr new file mode 100644 index 000000000000..6ca8ec6bd1a5 --- /dev/null +++ b/tests/ui/dyn-compatibility/unsafe-binders-bare-trait-object-next-solver.stderr @@ -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 &'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 + --> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:10:21 + | +LL | trait Foo: Deref &'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`.