From f6efe7e1d52abab87cd897fb96ccc6bad68c64b3 Mon Sep 17 00:00:00 2001 From: Adwin White Date: Mon, 26 Jan 2026 17:12:32 +0800 Subject: [PATCH] don't return incorrectly constrained opaques in `method_autoderef_steps` --- compiler/rustc_hir_typeck/src/method/probe.rs | 36 ++++++++++++---- .../src/infer/canonical/query_response.rs | 6 ++- .../opaques/method_autoderef_constraints.rs | 38 ++++++++++++++++ .../method_autoderef_constraints.stderr | 43 +++++++++++++++++++ 4 files changed, 113 insertions(+), 10 deletions(-) create mode 100644 tests/ui/traits/next-solver/opaques/method_autoderef_constraints.rs create mode 100644 tests/ui/traits/next-solver/opaques/method_autoderef_constraints.stderr diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 31ca0e46091cc..2a92a4b48edcc 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -415,10 +415,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { infcx.instantiate_canonical(span, &query_input.canonical); let query::MethodAutoderefSteps { predefined_opaques_in_body: _, self_ty } = value; debug!(?self_ty, ?query_input, "probe_op: Mode::Path"); + let prev_opaque_entries = self.inner.borrow_mut().opaque_types().num_entries(); MethodAutoderefStepsResult { steps: infcx.tcx.arena.alloc_from_iter([CandidateStep { - self_ty: self - .make_query_response_ignoring_pending_obligations(var_values, self_ty), + self_ty: self.make_query_response_ignoring_pending_obligations( + var_values, + self_ty, + prev_opaque_entries, + ), self_ty_is_opaque: false, autoderefs: 0, from_unsafe_deref: false, @@ -607,6 +611,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_types_storage`"); } } + let prev_opaque_entries = infcx.inner.borrow_mut().opaque_types().num_entries(); // We accept not-yet-defined opaque types in the autoderef // chain to support recursive calls. We do error if the final @@ -650,8 +655,11 @@ pub(crate) fn method_autoderef_steps<'tcx>( .zip(reachable_via_deref) .map(|((ty, d), reachable_via_deref)| { let step = CandidateStep { - self_ty: infcx - .make_query_response_ignoring_pending_obligations(inference_vars, ty), + self_ty: infcx.make_query_response_ignoring_pending_obligations( + inference_vars, + ty, + prev_opaque_entries, + ), self_ty_is_opaque: self_ty_is_opaque(ty), autoderefs: d, from_unsafe_deref: reached_raw_pointer, @@ -671,8 +679,11 @@ pub(crate) fn method_autoderef_steps<'tcx>( .by_ref() .map(|(ty, d)| { let step = CandidateStep { - self_ty: infcx - .make_query_response_ignoring_pending_obligations(inference_vars, ty), + self_ty: infcx.make_query_response_ignoring_pending_obligations( + inference_vars, + ty, + prev_opaque_entries, + ), self_ty_is_opaque: self_ty_is_opaque(ty), autoderefs: d, from_unsafe_deref: reached_raw_pointer, @@ -692,11 +703,19 @@ pub(crate) fn method_autoderef_steps<'tcx>( let opt_bad_ty = match final_ty.kind() { ty::Infer(ty::TyVar(_)) if !self_ty_is_opaque(final_ty) => Some(MethodAutoderefBadTy { reached_raw_pointer, - ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty), + ty: infcx.make_query_response_ignoring_pending_obligations( + inference_vars, + final_ty, + prev_opaque_entries, + ), }), ty::Error(_) => Some(MethodAutoderefBadTy { reached_raw_pointer, - ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty), + ty: infcx.make_query_response_ignoring_pending_obligations( + inference_vars, + final_ty, + prev_opaque_entries, + ), }), ty::Array(elem_ty, _) => { let autoderefs = steps.iter().filter(|s| s.reachable_via_deref).count() - 1; @@ -704,6 +723,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( self_ty: infcx.make_query_response_ignoring_pending_obligations( inference_vars, Ty::new_slice(infcx.tcx, *elem_ty), + prev_opaque_entries, ), self_ty_is_opaque: false, autoderefs, diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 65b0f82114329..846123b8aad93 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -24,7 +24,8 @@ use crate::infer::canonical::{ }; use crate::infer::region_constraints::RegionConstraintData; use crate::infer::{ - DefineOpaqueTypes, InferCtxt, InferOk, InferResult, SubregionOrigin, TypeOutlivesConstraint, + DefineOpaqueTypes, InferCtxt, InferOk, InferResult, OpaqueTypeStorageEntries, SubregionOrigin, + TypeOutlivesConstraint, }; use crate::traits::query::NoSolution; use crate::traits::{ObligationCause, PredicateObligations, ScrubbedTraitError, TraitEngine}; @@ -81,6 +82,7 @@ impl<'tcx> InferCtxt<'tcx> { &self, inference_vars: CanonicalVarValues<'tcx>, answer: T, + prev_entries: OpaqueTypeStorageEntries, ) -> Canonical<'tcx, QueryResponse<'tcx, T>> where T: Debug + TypeFoldable>, @@ -96,7 +98,7 @@ impl<'tcx> InferCtxt<'tcx> { self.inner .borrow_mut() .opaque_type_storage - .iter_opaque_types() + .opaque_types_added_since(prev_entries) .map(|(k, v)| (k, v.ty)) .collect() } else { diff --git a/tests/ui/traits/next-solver/opaques/method_autoderef_constraints.rs b/tests/ui/traits/next-solver/opaques/method_autoderef_constraints.rs new file mode 100644 index 0000000000000..d8375a62bb376 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/method_autoderef_constraints.rs @@ -0,0 +1,38 @@ +//@ compile-flags: -Znext-solver + +// Regression test for trait-system-refactor-initiative/issues/263 +// Previously `method_auto_deref_steps` would also return opaque +// types which have already been defined in the parent context. +// +// We then handled these opaque types by emitting `AliasRelate` goals +// when instantiating its result, assuming that operation to be infallible. +// By returning opaque type constraints from the parent context and +// constraining the hidden type without reproving the item bounds of +// the opaque, this ended up causing ICE. + +use std::ops::Deref; +trait Trait {} +struct Inv(*mut T); +impl Trait for i32 {} +impl Deref for Inv { + type Target = u32; + fn deref(&self) -> &Self::Target { + todo!() + } +} + +fn mk() -> T { todo!() } +fn foo() -> Inv { + //~^ ERROR: the trait bound `u32: Trait` is not satisfied [E0277] + let mut x: Inv<_> = mk(); + if false { + return x; + //~^ ERROR: the trait bound `u32: Trait` is not satisfied [E0277] + } + + x.count_ones(); + x + //~^ ERROR: mismatched types [E0308] +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/opaques/method_autoderef_constraints.stderr b/tests/ui/traits/next-solver/opaques/method_autoderef_constraints.stderr new file mode 100644 index 0000000000000..c421222309a03 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/method_autoderef_constraints.stderr @@ -0,0 +1,43 @@ +error[E0277]: the trait bound `u32: Trait` is not satisfied + --> $DIR/method_autoderef_constraints.rs:29:16 + | +LL | return x; + | ^ the trait `Trait` is not implemented for `u32` + | +help: the trait `Trait` is implemented for `i32` + --> $DIR/method_autoderef_constraints.rs:16:1 + | +LL | impl Trait for i32 {} + | ^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/method_autoderef_constraints.rs:34:5 + | +LL | fn foo() -> Inv { + | --------------- + | | | + | | the expected opaque type + | expected `Inv` because of return type +... +LL | x + | ^ types differ + | + = note: expected struct `Inv` + found struct `Inv` + +error[E0277]: the trait bound `u32: Trait` is not satisfied + --> $DIR/method_autoderef_constraints.rs:25:1 + | +LL | fn foo() -> Inv { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `u32` + | +help: the trait `Trait` is implemented for `i32` + --> $DIR/method_autoderef_constraints.rs:16:1 + | +LL | impl Trait for i32 {} + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`.