From 608d4528b50fc311544e7cd2b9733bdb85a33ba8 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Fri, 21 Aug 2026 02:30:58 +0900 Subject: [PATCH 01/12] `-Znext-solver` Allow method calls on chains of assoc types of not-yet defined opaque types --- compiler/rustc_hir_analysis/src/autoderef.rs | 2 +- .../rustc_hir_analysis/src/check/check.rs | 10 +- compiler/rustc_hir_typeck/src/callee.rs | 2 +- compiler/rustc_hir_typeck/src/method/probe.rs | 61 +++-- .../src/infer/canonical/query_response.rs | 1 + compiler/rustc_infer/src/infer/context.rs | 40 +++- compiler/rustc_infer/src/infer/mod.rs | 49 +++- .../rustc_infer/src/infer/opaque_types/mod.rs | 53 +++++ .../src/infer/opaque_types/table.rs | 164 +++++++++++++- .../src/infer/snapshot/undo_log.rs | 6 +- compiler/rustc_middle/src/traits/query.rs | 3 +- compiler/rustc_middle/src/traits/solve.rs | 15 +- compiler/rustc_middle/src/ty/context.rs | 14 +- .../src/ty/context/impl_interner.rs | 10 + compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/opaque_types.rs | 2 + .../rustc_middle/src/ty/structural_impls.rs | 1 + .../src/canonical/canonicalizer.rs | 122 +++++++++- .../src/canonical/mod.rs | 35 ++- .../src/solve/assembly/mod.rs | 91 +++----- .../src/solve/eval_ctxt/fast_path.rs | 3 +- .../src/solve/eval_ctxt/mod.rs | 134 +++++++---- .../rustc_next_trait_solver/src/solve/mod.rs | 28 +++ .../src/solve/normalizes_to.rs | 46 +++- .../src/solve/project_goals/mod.rs | 22 ++ .../src/solve/project_goals/opaque_types.rs | 13 ++ .../src/solve/trait_goals.rs | 3 +- .../src/solve/delegate.rs | 1 + .../src/solve/fulfill.rs | 2 +- compiler/rustc_type_ir/src/infer_ctxt.rs | 41 +++- compiler/rustc_type_ir/src/inherent.rs | 6 +- compiler/rustc_type_ir/src/interner.rs | 11 + compiler/rustc_type_ir/src/opaque_ty.rs | 211 +++++++++++++++++- compiler/rustc_type_ir/src/solve/mod.rs | 12 +- ...non-defining-use-projection-on-hidden-1.rs | 27 +++ ...non-defining-use-projection-on-hidden-2.rs | 46 ++++ ...stall-on-no-actual-change-im-the-caller.rs | 76 +++++++ 37 files changed, 1183 insertions(+), 182 deletions(-) create mode 100644 tests/ui/traits/next-solver/opaques/non-defining-use-projection-on-hidden-1.rs create mode 100644 tests/ui/traits/next-solver/opaques/non-defining-use-projection-on-hidden-2.rs create mode 100644 tests/ui/traits/next-solver/opaques/non-defining-use-stall-on-no-actual-change-im-the-caller.rs diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 883bfa2b46b9b..2cf86878d1fcf 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -74,7 +74,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { // opaque type and instead return `None` in `fn overloaded_deref_ty` if the // opaque does not have a `Deref` item-bound. if let &ty::Infer(ty::TyVar(vid)) = self.state.cur_ty.kind() - && !self.infcx.has_opaques_with_sub_unified_hidden_type(vid) + && !self.infcx.has_hidden_types_of_opaques_modulo_sub_unification(vid) { return None; } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 1e75902884fe1..1d2e8606487f3 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -429,8 +429,11 @@ fn check_opaque_meets_bounds<'tcx>( let _ = infcx.take_opaque_types(); Ok(()) } else { + let (opaques, hiddens) = infcx.take_opaque_types(); + // We don't track anything on `hidden_types_of_opaques` in the old solver. + assert!(hiddens.is_empty()); // Check that any hidden types found during wf checking match the hidden types that `type_of` sees. - for (mut key, mut ty) in infcx.take_opaque_types() { + for (mut key, mut ty) in opaques { ty.ty = infcx.deeply_resolve_ignoring_regions(ty.ty); key = infcx.deeply_resolve_ignoring_regions(key); sanity_check_found_hidden_type(tcx, key, ty)?; @@ -2351,9 +2354,12 @@ pub(super) fn check_coroutine_obligations( } if !tcx.next_trait_solver_globally() { + let (opaques, hiddens) = infcx.take_opaque_types(); + // We don't track anything on `hidden_types_of_opaques` in the old solver. + assert!(hiddens.is_empty()); // Check that any hidden types found when checking these stalled coroutine obligations // are valid. - for (key, ty) in infcx.take_opaque_types() { + for (key, ty) in opaques { let hidden_type = infcx.deeply_resolve_ignoring_regions(ty); let key = infcx.deeply_resolve_ignoring_regions(key); sanity_check_found_hidden_type(tcx, key, hidden_type)?; diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 025c64896edb7..117cf83bbce62 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -336,7 +336,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Infer(ty::TyVar(vid)) => { // If we end up with an inference variable which is not the hidden type of // an opaque, emit an error. - if !self.has_opaques_with_sub_unified_hidden_type(vid) { + if !self.has_hidden_types_of_opaques_modulo_sub_unification(vid) { self.type_must_be_known_at_this_point(autoderef.span(), adjusted_ty); return None; } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index aee246a61fb1e..0010e12173661 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -418,7 +418,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { ty::List::empty() }; - let value = query::MethodAutoderefSteps { predefined_opaques_in_body, self_ty }; + let opaque_hidden_ty_bounds_in_body = if self.next_trait_solver() { + self.tcx.mk_opaque_hidden_ty_bounds_in_body_from_iter( + self.inner.borrow_mut().opaque_types().iter_opaque_hidden_ty_bounds(), + ) + } else { + ty::List::empty() + }; + let value = query::MethodAutoderefSteps { + predefined_opaques_in_body, + opaque_hidden_ty_bounds_in_body, + self_ty, + }; let query_input = self .canonicalize_query(ParamEnvAnd { param_env: self.param_env, value }, &mut orig_values); @@ -433,7 +444,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let infcx = &self.infcx; let (ParamEnvAnd { param_env: _, value }, var_values) = infcx.instantiate_canonical(span, &query_input.canonical); - let query::MethodAutoderefSteps { predefined_opaques_in_body: _, self_ty } = value; + let query::MethodAutoderefSteps { + predefined_opaques_in_body: _, + opaque_hidden_ty_bounds_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 { @@ -443,7 +458,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty, prev_opaque_entries, ), - self_ty_is_opaque: false, + self_ty_is_hidden_ty_of_opaque: false, autoderefs: 0, from_unsafe_deref: false, unsize: false, @@ -641,7 +656,12 @@ pub(crate) fn method_autoderef_steps<'tcx>( let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal); let ParamEnvAnd { param_env, - value: query::MethodAutoderefSteps { predefined_opaques_in_body, self_ty }, + value: + query::MethodAutoderefSteps { + predefined_opaques_in_body, + opaque_hidden_ty_bounds_in_body, + self_ty, + }, } = goal; for (key, ty) in predefined_opaques_in_body { let prev = infcx @@ -661,14 +681,15 @@ pub(crate) fn method_autoderef_steps<'tcx>( debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_types_storage`"); } } + infcx.add_opaque_hidden_ty_bounds_in_storage(opaque_hidden_ty_bounds_in_body); 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 // infer var is not an opaque. - let self_ty_is_opaque = |ty: Ty<'_>| { + let self_ty_is_hidden_ty_of_opaque = |ty: Ty<'_>| { if let &ty::Infer(ty::TyVar(vid)) = ty.kind() { - infcx.has_opaques_with_sub_unified_hidden_type(vid) + infcx.has_hidden_types_of_opaques_modulo_sub_unification(vid) } else { false } @@ -710,7 +731,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( ty, prev_opaque_entries, ), - self_ty_is_opaque: self_ty_is_opaque(ty), + self_ty_is_hidden_ty_of_opaque: self_ty_is_hidden_ty_of_opaque(ty), autoderefs: d, from_unsafe_deref: reached_raw_pointer, unsize: false, @@ -734,7 +755,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( ty, prev_opaque_entries, ), - self_ty_is_opaque: self_ty_is_opaque(ty), + self_ty_is_hidden_ty_of_opaque: self_ty_is_hidden_ty_of_opaque(ty), autoderefs: d, from_unsafe_deref: reached_raw_pointer, unsize: false, @@ -751,14 +772,16 @@ pub(crate) fn method_autoderef_steps<'tcx>( }; let final_ty = autoderef_via_deref.final_ty(); 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, - prev_opaque_entries, - ), - }), + ty::Infer(ty::TyVar(_)) if !self_ty_is_hidden_ty_of_opaque(final_ty) => { + Some(MethodAutoderefBadTy { + reached_raw_pointer, + 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( @@ -775,7 +798,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( Ty::new_slice(infcx.tcx, *elem_ty), prev_opaque_entries, ), - self_ty_is_opaque: false, + self_ty_is_hidden_ty_of_opaque: false, autoderefs, // this could be from an unsafe deref if we had // a *mut/const [T; N] @@ -2314,10 +2337,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } - // Check whether any opaque types in the autoderef chain have been + // Check whether any hidden type of opaque in the autoderef chain have been // constrained. for step in self.steps { - if step.self_ty_is_opaque { + if step.self_ty_is_hidden_ty_of_opaque { debug!(?step.autoderefs, ?step.self_ty, "self_type_is_opaque"); let constrained_opaque = self.probe(|_| { // If we fail to instantiate the self type of this diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 3a245a5b25759..c3a25e19d898e 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -160,6 +160,7 @@ impl<'tcx> InferCtxt<'tcx> { .borrow_mut() .opaque_type_storage .take_opaque_types() + .0 .map(|(k, v)| (k, v.ty)) .collect(); diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 38dab6ec4875d..0cadf7c8c8401 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -343,30 +343,41 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { fn opaque_types_storage_num_entries(&self) -> OpaqueTypeStorageEntries { self.inner.borrow_mut().opaque_types().num_entries() } + fn num_opaque_hidden_ty_bounds(&self) -> usize { + self.inner.borrow_mut().opaque_types().num_opaque_hidden_ty_bounds() + } fn clone_opaque_types_lookup_table(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { self.inner.borrow_mut().opaque_types().iter_lookup_table().map(|(k, h)| (k, h.ty)).collect() } - fn clone_duplicate_opaque_types(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { + fn clone_opaque_hidden_ty_bounds(&self) -> Vec<(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)> { + self.inner.borrow_mut().opaque_types().iter_opaque_hidden_ty_bounds().collect() + } + fn clone_opaque_types_added_since( + &self, + prev_entries: OpaqueTypeStorageEntries, + ) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { self.inner .borrow_mut() .opaque_types() - .iter_duplicate_entries() + .opaque_types_added_since(prev_entries) .map(|(k, h)| (k, h.ty)) .collect() } - fn clone_opaque_types_added_since( + fn clone_opaque_hidden_ty_bounds_added_since( &self, prev_entries: OpaqueTypeStorageEntries, - ) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { + ) -> Vec<(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)> { self.inner .borrow_mut() .opaque_types() - .opaque_types_added_since(prev_entries) - .map(|(k, h)| (k, h.ty)) + .opaque_hidden_ty_bounds_added_since(prev_entries) .collect() } - fn opaques_with_sub_unified_hidden_type(&self, ty: ty::TyVid) -> Vec> { - self.opaques_with_sub_unified_hidden_type(ty) + fn hidden_types_of_opaques_modulo_sub_unification( + &self, + ty_vid: ty::TyVid, + ) -> Vec<(Ty<'tcx>, Vec>)> { + self.hidden_types_of_opaques_modulo_sub_unification(ty_vid) } fn register_hidden_type_in_storage( @@ -391,6 +402,19 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { .opaque_types() .add_duplicate(opaque_type_key, ty::ProvisionalHiddenType { span, ty: hidden_ty }) } + fn add_hidden_type_of_opaque_in_storage( + &self, + hidden_ty: Ty<'tcx>, + bounds: impl IntoIterator>, + ) { + self.add_hidden_type_of_opaque_in_storage(hidden_ty, bounds); + } + fn add_opaque_hidden_ty_bounds_in_storage( + &self, + bounds: &[(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)], + ) { + self.add_opaque_hidden_ty_bounds_in_storage(bounds); + } fn reset_opaque_types(&self) { let _ = self.take_opaque_types(); diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index e02cc9a7acd1f..3b3c19edc7f11 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -12,7 +12,7 @@ use region_constraints::{ GenericKind, RegionConstraintCollector, RegionConstraintStorage, VarInfos, VerifyBound, }; pub use relate::combine::PredicateEmittingRelation; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::undo_log::{Rollback, UndoLogs}; use rustc_data_structures::unify::{self as ut, UnifyKey, UnifyValue}; @@ -1118,8 +1118,15 @@ impl<'tcx> InferCtxt<'tcx> { } #[instrument(level = "debug", skip(self), ret)] - pub fn take_opaque_types(&self) -> Vec<(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)> { - self.inner.borrow_mut().opaque_type_storage.take_opaque_types().collect() + pub fn take_opaque_types( + &self, + ) -> ( + Vec<(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)>, + Vec<(Ty<'tcx>, FxIndexSet>)>, + ) { + let mut inner = self.inner.borrow_mut(); + let (opaques, hiddens) = inner.opaque_type_storage.take_opaque_types(); + (opaques.collect(), hiddens.collect()) } #[instrument(level = "debug", skip(self), ret)] @@ -1127,7 +1134,7 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().opaque_type_storage.iter_opaque_types().collect() } - pub fn has_opaques_with_sub_unified_hidden_type(&self, ty_vid: TyVid) -> bool { + pub fn has_hidden_types_of_opaques_modulo_sub_unification(&self, ty_vid: TyVid) -> bool { if !self.next_trait_solver() { return false; } @@ -1135,8 +1142,8 @@ impl<'tcx> InferCtxt<'tcx> { let ty_sub_vid = self.sub_unification_table_root_var(ty_vid); let inner = &mut *self.inner.borrow_mut(); let mut type_variables = inner.type_variable_storage.with_log(&mut inner.undo_log); - inner.opaque_type_storage.iter_opaque_types().any(|(_, hidden_ty)| { - if let ty::Infer(ty::TyVar(hidden_vid)) = *hidden_ty.ty.kind() { + inner.opaque_type_storage.iter_hidden_types_of_opaques().any(|(hidden_ty, _)| { + if let ty::Infer(ty::TyVar(hidden_vid)) = *hidden_ty.kind() { let opaque_sub_vid = type_variables.sub_unification_table_root_var(hidden_vid); if opaque_sub_vid == ty_sub_vid { return true; @@ -1184,6 +1191,36 @@ impl<'tcx> InferCtxt<'tcx> { .collect() } + pub fn hidden_types_of_opaques_modulo_sub_unification( + &self, + ty_vid: TyVid, + ) -> Vec<(Ty<'tcx>, Vec>)> { + // Avoid accidentally allowing more code to compile with the old solver. + if !self.next_trait_solver() { + return vec![]; + } + + let ty_sub_vid = self.sub_unification_table_root_var(ty_vid); + let inner = &mut *self.inner.borrow_mut(); + // This is iffy, can't call `type_variables()` as we're already + // borrowing the `opaque_type_storage` here. + let mut type_variables = inner.type_variable_storage.with_log(&mut inner.undo_log); + inner + .opaque_type_storage + .iter_hidden_types_of_opaques() + .filter_map(|(hidden_ty, bounds)| { + if let ty::Infer(ty::TyVar(hidden_vid)) = *hidden_ty.kind() { + let opaque_sub_vid = type_variables.sub_unification_table_root_var(hidden_vid); + if opaque_sub_vid == ty_sub_vid { + return Some((hidden_ty, bounds.iter().copied().collect())); + } + } + + None + }) + .collect() + } + #[inline(always)] pub fn can_define_opaque_ty(&self, id: impl Into) -> bool { debug_assert!(!self.next_trait_solver()); diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 3cca843157b8f..faade40e51df0 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -207,6 +207,59 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().opaque_types().register(opaque_type_key, hidden_ty) } + pub fn add_hidden_type_of_opaque_in_storage( + &self, + hidden_ty: Ty<'tcx>, + bounds: impl IntoIterator>, + ) { + let ty::Infer(ty::TyVar(vid)) = *hidden_ty.kind() else { + return; + }; + if self.try_resolve_ty_var(vid).is_ok() { + return; + } + + let ty_sub_vid = self.sub_unification_table_root_var(vid); + let inner = &mut *self.inner.borrow_mut(); + // This is iffy, can't call `type_variables()` as we're already + // borrowing the `opaque_type_storage` here. + let mut type_variables = inner.type_variable_storage.with_log(&mut inner.undo_log); + + // Since we lookup `hidden_types_of_opaques` modulo sub-roots, + // it's okay to save them with the preexisting key that + // sub-unified with the given `hidden_ty`. + // + // And doing so helps avoiding possibly duplicates (modulo sub roots) + // which is not so good for caching and goal evaluation progress + // heuristics. + let hidden_ty = inner + .opaque_type_storage + .iter_hidden_types_of_opaques() + .map(|(hidden_ty, _)| hidden_ty) + .find(|hidden_ty| { + if let ty::Infer(ty::TyVar(hidden_vid)) = *hidden_ty.kind() { + type_variables.sub_unification_table_root_var(hidden_vid) == ty_sub_vid + } else { + false + } + }) + .unwrap_or(hidden_ty); + + inner.opaque_types().add_hidden_type_of_opaque(hidden_ty, bounds); + } + + pub fn add_opaque_hidden_ty_bounds_in_storage( + &self, + bounds: &[(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)], + ) { + for chunk in bounds.chunk_by(|a, b| a.0 == b.0) { + self.add_hidden_type_of_opaque_in_storage( + chunk[0].0, + chunk.iter().map(|(_, bound)| *bound), + ); + } + } + /// Insert a hidden type into the opaque type storage, equating it /// with any previous entries if necessary. /// diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index 6c738af439af2..02dc3e6a37536 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -1,8 +1,10 @@ +use std::iter; use std::ops::Deref; -use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::indexmap::map::Entry; use rustc_data_structures::undo_log::UndoLogs; -use rustc_middle::ty::{OpaqueTypeKey, ProvisionalHiddenType, Ty}; +use rustc_middle::ty::{self as ty, OpaqueTypeKey, ProvisionalHiddenType, Ty}; use rustc_span::bug; use tracing::instrument; @@ -12,6 +14,18 @@ use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog}; pub struct OpaqueTypeStorage<'tcx> { opaque_types: FxIndexMap, ProvisionalHiddenType<'tcx>>, duplicate_entries: Vec<(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)>, + // Note: + // OpaqueHiddenTy ::= OpaqueTy + // | Projection + // + // When we normalize a `OpaqueHiddenTy`, we store its self-bounds here, to support non-defining + // usages of sucu hidden types. The key is an expected term for the normalization and the value + // is those self-bounds. + hidden_types_of_opaques: FxIndexMap, FxIndexSet>>, + // The flattened version of the above `hidden_types_of_opaques`. This is a pure duplication + // but we need this to track things linearly, so that we can track the number of those bounds + // in `OpaqueTypeStorageEntries` without a map and can lookup `opaque_hidden_ty_bounds` in O(1). + opaque_hidden_ty_bounds: Vec<(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)>, } /// The number of entries in the opaque type storage at a given point. @@ -22,11 +36,17 @@ pub struct OpaqueTypeStorage<'tcx> { pub struct OpaqueTypeStorageEntries { opaque_types: usize, duplicate_entries: usize, + opaque_hidden_ty_bounds: usize, } impl rustc_type_ir::inherent::OpaqueTypeStorageEntries for OpaqueTypeStorageEntries { - fn needs_reevaluation(self, canonicalized: usize) -> bool { - self.opaque_types != canonicalized + fn needs_reevaluation(self, opaques: usize, hidden_ty_bounds: usize) -> bool { + let OpaqueTypeStorageEntries { + opaque_types, + duplicate_entries: _, + opaque_hidden_ty_bounds, + } = self; + opaques != opaque_types || hidden_ty_bounds != opaque_hidden_ty_bounds } } @@ -40,7 +60,6 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { if let Some(prev) = prev { *self.opaque_types.get_mut(&key).unwrap() = prev; } else { - // FIXME(#120456) - is `swap_remove` correct? match self.opaque_types.swap_remove(&key) { None => bug!("reverted opaque type inference that was never registered: {:?}", key), Some(_) => {} @@ -53,25 +72,77 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { assert!(entry.is_some()); } + pub(crate) fn truncate_hidden_types_of_opaques( + &mut self, + hidden_ty: Ty<'tcx>, + len: Option, + ) { + let removed = if let Some(len) = len { + let bounds = self.hidden_types_of_opaques.get_mut(&hidden_ty).unwrap(); + let removed = bounds.len() - len; + bounds.truncate(len); + removed + } else { + match self.hidden_types_of_opaques.swap_remove(&hidden_ty) { + None => bug!( + "reverted opaque hidden type inference that was never registered: {:?}", + hidden_ty + ), + Some(bounds) => bounds.len(), + } + }; + + let truncate_to = self.opaque_hidden_ty_bounds.len() - removed; + debug_assert!( + (&self.opaque_hidden_ty_bounds[truncate_to..]).iter().all(|(h, _)| *h == hidden_ty) + ); + self.opaque_hidden_ty_bounds.truncate(truncate_to); + } + pub fn is_empty(&self) -> bool { - let OpaqueTypeStorage { opaque_types, duplicate_entries } = self; - opaque_types.is_empty() && duplicate_entries.is_empty() + let OpaqueTypeStorage { + opaque_types, + duplicate_entries, + hidden_types_of_opaques, + opaque_hidden_ty_bounds, + } = self; + opaque_types.is_empty() + && duplicate_entries.is_empty() + && hidden_types_of_opaques.is_empty() + && opaque_hidden_ty_bounds.is_empty() } pub(crate) fn take_opaque_types( &mut self, - ) -> impl Iterator, ProvisionalHiddenType<'tcx>)> { - let OpaqueTypeStorage { opaque_types, duplicate_entries } = self; - std::mem::take(opaque_types).into_iter().chain(std::mem::take(duplicate_entries)) + ) -> ( + impl Iterator, ProvisionalHiddenType<'tcx>)>, + impl Iterator, FxIndexSet>)>, + ) { + let OpaqueTypeStorage { + opaque_types, + duplicate_entries, + hidden_types_of_opaques, + opaque_hidden_ty_bounds, + } = self; + let _ = std::mem::take(opaque_hidden_ty_bounds); + ( + std::mem::take(opaque_types).into_iter().chain(std::mem::take(duplicate_entries)), + std::mem::take(hidden_types_of_opaques).into_iter(), + ) } pub fn num_entries(&self) -> OpaqueTypeStorageEntries { OpaqueTypeStorageEntries { opaque_types: self.opaque_types.len(), duplicate_entries: self.duplicate_entries.len(), + opaque_hidden_ty_bounds: self.opaque_hidden_ty_bounds.len(), } } + pub fn num_opaque_hidden_ty_bounds(&self) -> usize { + self.opaque_hidden_ty_bounds.len() + } + pub fn opaque_types_added_since( &self, prev_entries: OpaqueTypeStorageEntries, @@ -83,6 +154,12 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { .chain(self.duplicate_entries.iter().skip(prev_entries.duplicate_entries).copied()) } + pub fn opaque_hidden_ty_bounds_added_since( + &self, + prev_entries: OpaqueTypeStorageEntries, + ) -> impl Iterator, ty::OpaqueHiddenTyBound<'tcx>)> { + self.opaque_hidden_ty_bounds.iter().skip(prev_entries.opaque_hidden_ty_bounds).copied() + } /// Only returns the opaque types from the lookup table. These are used /// when normalizing opaque types and have a unique key. /// @@ -108,10 +185,39 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { pub fn iter_opaque_types( &self, ) -> impl Iterator, ProvisionalHiddenType<'tcx>)> { - let OpaqueTypeStorage { opaque_types, duplicate_entries } = self; + let OpaqueTypeStorage { + opaque_types, + duplicate_entries, + hidden_types_of_opaques: _, + opaque_hidden_ty_bounds: _, + } = self; opaque_types.iter().map(|(k, v)| (*k, *v)).chain(duplicate_entries.iter().copied()) } + pub fn iter_hidden_types_of_opaques( + &self, + ) -> impl Iterator, &FxIndexSet>)> { + let OpaqueTypeStorage { + opaque_types: _, + duplicate_entries: _, + hidden_types_of_opaques, + opaque_hidden_ty_bounds: _, + } = self; + hidden_types_of_opaques.iter().map(|(hidden, bounds)| (*hidden, bounds)) + } + + pub fn iter_opaque_hidden_ty_bounds( + &self, + ) -> impl Iterator, ty::OpaqueHiddenTyBound<'tcx>)> { + let OpaqueTypeStorage { + opaque_types: _, + duplicate_entries: _, + hidden_types_of_opaques: _, + opaque_hidden_ty_bounds, + } = self; + opaque_hidden_ty_bounds.iter().copied() + } + #[inline] pub(crate) fn with_log<'a>( &'a mut self, @@ -158,4 +264,40 @@ impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> { self.storage.duplicate_entries.push((key, hidden_type)); self.undo_log.push(UndoLog::DuplicateOpaqueType); } + + pub fn add_hidden_type_of_opaque( + &mut self, + hidden_ty: Ty<'tcx>, + bounds: impl IntoIterator>, + ) { + let OpaqueTypeStorage { + opaque_types: _, + duplicate_entries: _, + hidden_types_of_opaques, + opaque_hidden_ty_bounds, + } = self.storage; + let prev_len = match hidden_types_of_opaques.entry(hidden_ty) { + Entry::Occupied(mut entry) => { + let entry = entry.get_mut(); + let len = entry.len(); + entry.extend(bounds); + if entry.len() == len { + return; + } + opaque_hidden_ty_bounds + .extend(iter::repeat(hidden_ty).zip(entry.iter().skip(len).copied())); + Some(len) + } + Entry::Vacant(vacant) => { + let bounds: FxIndexSet<_> = bounds.into_iter().collect(); + if bounds.is_empty() { + return; + } + let entry = vacant.insert(bounds); + opaque_hidden_ty_bounds.extend(iter::repeat(hidden_ty).zip(entry.iter().copied())); + None + } + }; + self.undo_log.push(UndoLog::HiddenTypesOfOpaques(hidden_ty, prev_len)); + } } diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs index 2b1ac29173483..a4e55945e819e 100644 --- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs +++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use rustc_data_structures::undo_log::{Rollback, UndoLogs}; use rustc_data_structures::{snapshot_vec as sv, unify as ut}; -use rustc_middle::ty::{self, OpaqueTypeKey, ProvisionalHiddenType}; +use rustc_middle::ty::{self, OpaqueTypeKey, ProvisionalHiddenType, Ty}; use tracing::debug; use crate::infer::unify_key::{ConstVidKey, RegionVidKey}; @@ -20,6 +20,7 @@ pub struct Snapshot<'tcx> { pub(crate) enum UndoLog<'tcx> { DuplicateOpaqueType, OpaqueTypes(OpaqueTypeKey<'tcx>, Option>), + HiddenTypesOfOpaques(Ty<'tcx>, Option), TypeVariables(type_variable::UndoLog<'tcx>), ConstUnificationTable(sv::UndoLog>>), IntUnificationTable(sv::UndoLog>), @@ -67,6 +68,9 @@ impl<'tcx> Rollback> for InferCtxtInner<'tcx> { match undo { UndoLog::DuplicateOpaqueType => self.opaque_type_storage.pop_duplicate_entry(), UndoLog::OpaqueTypes(key, idx) => self.opaque_type_storage.remove(key, idx), + UndoLog::HiddenTypesOfOpaques(ty, len) => { + self.opaque_type_storage.truncate_hidden_types_of_opaques(ty, len) + } UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo), UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo), UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo), diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index f2a2c6c3f4a63..1fa9348821590 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -70,6 +70,7 @@ pub struct MethodAutoderefSteps<'tcx> { /// /// Only used by the new solver for now. pub predefined_opaques_in_body: solve::PredefinedOpaques<'tcx>, + pub opaque_hidden_ty_bounds_in_body: solve::OpaqueHiddenTyBounds<'tcx>, pub self_ty: Ty<'tcx>, } @@ -155,7 +156,7 @@ impl<'tcx> FromIterator> for DropckConstraint<'tcx> { #[derive(Debug, StableHash)] pub struct CandidateStep<'tcx> { pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, - pub self_ty_is_opaque: bool, + pub self_ty_is_hidden_ty_of_opaque: bool, pub autoderefs: usize, /// `true` if the type results from a dereference of a raw pointer. /// when assembling candidates, we include these steps, but not when diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 02f9ef365f288..c00eacf6e330f 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -21,6 +21,7 @@ pub type GoalStalledOnOpaques<'tcx> = ir::solve::GoalStalledOnOpaques = ir::solve::SucceededInErased>; pub type PredefinedOpaques<'tcx> = &'tcx ty::List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>; +pub type OpaqueHiddenTyBounds<'tcx> = &'tcx ty::List<(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)>; // Interning CanonicalInput drastically reduces max memory usage when compiling a crate that has // trait solver recursion depth overflows with next-solver deduplicating individual inputs. @@ -72,11 +73,8 @@ impl<'tcx> TypeFoldable> for ExternalConstraints<'tcx> { Ok(FallibleTypeFolder::cx(folder).mk_external_constraints(ExternalConstraintsData { region_constraints: self.region_constraints.clone().try_fold_with(folder)?, - opaque_types: self - .opaque_types - .iter() - .map(|opaque| opaque.try_fold_with(folder)) - .collect::>()?, + opaque_types: self.opaque_types.try_fold_with(folder)?, + opaque_hidden_ty_bounds: self.opaque_hidden_ty_bounds.try_fold_with(folder)?, normalization_nested_goals: self .normalization_nested_goals .clone() @@ -94,7 +92,8 @@ impl<'tcx> TypeFoldable> for ExternalConstraints<'tcx> { TypeFolder::cx(folder).mk_external_constraints(ExternalConstraintsData { region_constraints: self.region_constraints.clone().fold_with(folder), - opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(), + opaque_types: self.opaque_types.fold_with(folder), + opaque_hidden_ty_bounds: self.opaque_hidden_ty_bounds.fold_with(folder), normalization_nested_goals: self.normalization_nested_goals.clone().fold_with(folder), }) } @@ -105,11 +104,13 @@ impl<'tcx> TypeVisitable> for ExternalConstraints<'tcx> { let ExternalConstraintsData { region_constraints, opaque_types, + opaque_hidden_ty_bounds, normalization_nested_goals, } = &**self; try_visit!(region_constraints.visit_with(visitor)); try_visit!(opaque_types.visit_with(visitor)); + try_visit!(opaque_hidden_ty_bounds.visit_with(visitor)); normalization_nested_goals.visit_with(visitor) } } @@ -121,6 +122,6 @@ mod size_asserts { use super::*; // tidy-alphabetical-start - static_assert_size!(GoalStalledOn<'_>, 56); + static_assert_size!(GoalStalledOn<'_>, 64); // tidy-alphabetical-end } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index b6e204dd52a11..411ace170870e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -66,7 +66,7 @@ use crate::thir::Thir; use crate::traits; use crate::traits::solve::{ CanonicalInput, CanonicalInputData, ExternalConstraints, ExternalConstraintsData, - PredefinedOpaques, + OpaqueHiddenTyBounds, PredefinedOpaques, }; use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; use crate::ty::{ @@ -159,6 +159,8 @@ pub struct CtxtInterners<'tcx> { adt_def: InternedSet<'tcx, AdtDefData>, external_constraints: InternedSet<'tcx, ExternalConstraintsData>>, predefined_opaques_in_body: InternedSet<'tcx, List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>>, + hidden_types_of_opaques_in_body: + InternedSet<'tcx, List<(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)>>, fields: InternedSet<'tcx, List>, local_def_ids: InternedSet<'tcx, List>, captures: InternedSet<'tcx, List<&'tcx ty::CapturedPlace<'tcx>>>, @@ -198,6 +200,7 @@ impl<'tcx> CtxtInterners<'tcx> { adt_def: InternedSet::with_capacity(N), external_constraints: InternedSet::with_capacity(N), predefined_opaques_in_body: InternedSet::with_capacity(N), + hidden_types_of_opaques_in_body: InternedSet::with_capacity(N * 2), fields: InternedSet::with_capacity(N * 4), local_def_ids: InternedSet::with_capacity(N), captures: InternedSet::with_capacity(N), @@ -2063,6 +2066,7 @@ slice_interners!( patterns: pub mk_patterns(Pattern<'tcx>), outlives: pub mk_outlives(ty::ArgOutlivesClause<'tcx>), predefined_opaques_in_body: pub mk_predefined_opaques_in_body((ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)), + hidden_types_of_opaques_in_body: pub mk_opaque_hidden_ty_bounds_in_body((Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)), ); impl<'tcx> TyCtxt<'tcx> { @@ -2558,6 +2562,14 @@ impl<'tcx> TyCtxt<'tcx> { T::collect_and_apply(iter, |xs| self.mk_predefined_opaques_in_body(xs)) } + pub fn mk_opaque_hidden_ty_bounds_in_body_from_iter(self, iter: I) -> T::Output + where + I: Iterator, + T: CollectAndApply<(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>), OpaqueHiddenTyBounds<'tcx>>, + { + T::collect_and_apply(iter, |xs| self.mk_opaque_hidden_ty_bounds_in_body(xs)) + } + pub fn mk_clauses_from_iter(self, iter: I) -> T::Output where I: Iterator, diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index a6688b668aab3..880a2c6b59c67 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -75,6 +75,16 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) -> Self::PredefinedOpaques { self.mk_predefined_opaques_in_body(data) } + + type OpaqueHiddenTyBounds = solve::OpaqueHiddenTyBounds<'tcx>; + + fn mk_opaque_hidden_ty_bounds_in_body( + self, + data: &[(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)], + ) -> Self::OpaqueHiddenTyBounds { + self.mk_opaque_hidden_ty_bounds_in_body(data) + } + type LocalDefIds = &'tcx ty::List; type CanonicalVarKinds = CanonicalVarKinds<'tcx>; fn mk_canonical_var_kinds( diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 1f2ffb17cc2c7..1b96272e56902 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -79,7 +79,7 @@ pub use self::fold::*; pub use self::instance::{Instance, InstanceKind, ReifyReason, ShimKind}; pub(crate) use self::list::RawList; pub use self::list::{List, ListWithCachedTypeInfo}; -pub use self::opaque_types::OpaqueTypeKey; +pub use self::opaque_types::{OpaqueHiddenTyBound, OpaqueTypeKey}; pub use self::pattern::{Pattern, PatternKind}; pub use self::predicate::{ AliasTerm, AliasTermKind, ArgOutlivesClause, Clause, ClauseKind, CoercePredicate, diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index 7333d17e259e0..293e7268c3f89 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -10,6 +10,8 @@ use crate::ty::{ pub type OpaqueTypeKey<'tcx> = rustc_type_ir::OpaqueTypeKey>; +pub type OpaqueHiddenTyBound<'tcx> = rustc_type_ir::OpaqueHiddenTyBound>; + /// Converts generic params of a TypeFoldable from one /// item's generics to another. Usually from a function's generics /// list to the opaque type's own generics. diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 3710a159b3fdd..2549b11acabf5 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -760,6 +760,7 @@ macro_rules! list_fold { list_fold! { &'tcx ty::List> : mk_poly_existential_predicates, &'tcx ty::List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>: mk_predefined_opaques_in_body, + &'tcx ty::List<(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)>: mk_opaque_hidden_ty_bounds_in_body, &'tcx ty::List> : mk_place_elems, &'tcx ty::List> : mk_patterns, &'tcx ty::List> : mk_outlives, diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 75c7513758cd0..8e85b5cc43537 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -2,15 +2,17 @@ use std::collections::hash_map::Entry; use std::mem; use rustc_type_ir::inherent::*; -use rustc_type_ir::solve::{Goal, QueryInput}; +use rustc_type_ir::solve::{Certainty, ExternalConstraintsData, Goal, QueryInput, Response}; use rustc_type_ir::{ - self as ty, Canonical, CanonicalParamEnvCacheEntry, CanonicalVarKind, CanonicalizerState, - Const, Flags, InferCtxtLike, Interner, PlaceholderConst, PlaceholderType, PredicateProxy, - Region, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, + self as ty, Canonical, CanonicalParamEnvCacheEntry, CanonicalVarKind, CanonicalVarValues, + CanonicalizerState, Const, Flags, InferCtxtLike, Interner, PlaceholderConst, PlaceholderType, + PredicateProxy, Region, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitableExt, }; use thin_vec::ThinVec; use crate::delegate::SolverDelegate; +use crate::solve::RawExternalConstraintsData; /// Does this have infer/placeholder/param, free regions or ReErased? const NEEDS_CANONICAL: TypeFlags = TypeFlags::from_bits( @@ -95,6 +97,87 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { Canonical { max_universe, var_kinds, value } } + pub(super) fn canonicalize_query_response( + delegate: &'a D, + max_input_universe: ty::UniverseIndex, + var_values: CanonicalVarValues, + certainty: Certainty, + external_constraints: RawExternalConstraintsData, + ) -> ty::Canonical> { + let mut canonicalizer = + Canonicalizer::new(delegate, CanonicalizeMode::Response { max_input_universe }); + + let var_values = if var_values.has_type_flags(NEEDS_CANONICAL) { + var_values.fold_with(&mut canonicalizer) + } else { + var_values + }; + + let RawExternalConstraintsData { + region_constraints, + opaque_types, + opaque_hidden_ty_bounds: mut opaque_hidden_ty_bounds_candidates, + normalization_nested_goals, + } = external_constraints; + let region_constraints = if region_constraints.has_type_flags(NEEDS_CANONICAL) { + region_constraints.fold_with(&mut canonicalizer) + } else { + region_constraints + }; + let opaque_types = if opaque_types.has_type_flags(NEEDS_CANONICAL) { + opaque_types.fold_with(&mut canonicalizer) + } else { + opaque_types + }; + let normalization_nested_goals = + if normalization_nested_goals.has_type_flags(NEEDS_CANONICAL) { + normalization_nested_goals.fold_with(&mut canonicalizer) + } else { + normalization_nested_goals + }; + + // Filter out irrelevant hidden tys, in a fixed-point iteration to make them less bulky. + let mut opaque_hidden_ty_bounds = vec![]; + while !opaque_hidden_ty_bounds_candidates.is_empty() { + let prev_len = opaque_hidden_ty_bounds.len(); + opaque_hidden_ty_bounds_candidates.retain(|bounds @ (hidden_ty, _)| { + if let ty::Infer(ty::TyVar(vid)) = hidden_ty.kind() + && canonicalizer + .state + .sub_root_lookup_table + .contains_key(&delegate.sub_unification_table_root_var(vid)) + { + opaque_hidden_ty_bounds.push(bounds.clone().fold_with(&mut canonicalizer)); + false + } else { + true + } + }); + if opaque_hidden_ty_bounds.len() == prev_len { + break; + } + } + + let value = Response { + certainty, + var_values, + external_constraints: delegate.cx().mk_external_constraints(ExternalConstraintsData { + region_constraints, + opaque_types: delegate.cx().mk_predefined_opaques_in_body(&opaque_types), + opaque_hidden_ty_bounds: delegate + .cx() + .mk_opaque_hidden_ty_bounds_in_body(&opaque_hidden_ty_bounds), + normalization_nested_goals, + }), + }; + + debug_assert!(!value.has_infer(), "unexpected infer in {value:?}"); + debug_assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); + let (max_universe, _variables, var_kinds) = canonicalizer.finalize(); + + Canonical { max_universe, var_kinds, value } + } + // The return value is the canonicalized `param_env`, plus a canonicalizer suitable for // canonicalizing the rest of the input. (For efficiency, and when appropriate, the returned // canonicalizer will be the same one used on `param_env`, with suitable modifications.) @@ -219,7 +302,36 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { predefined_opaques_in_body }; - let value = QueryInput { goal, predefined_opaques_in_body }; + // Filter out irrelevant hidden tys, in a fixed-point iteration. Otherwise it would make + // the query heavy and less cache-friendly. + let mut hidden_types_of_opaques_in_body_candidates = + input.hidden_types_of_opaques_in_body.to_vec(); + let mut hidden_types_of_opaques_in_body = vec![]; + while !hidden_types_of_opaques_in_body_candidates.is_empty() { + let prev_len = hidden_types_of_opaques_in_body.len(); + hidden_types_of_opaques_in_body_candidates.retain(|bound @ (hidden_ty, _)| { + if let ty::Infer(ty::TyVar(vid)) = hidden_ty.kind() + && rest_canonicalizer + .state + .sub_root_lookup_table + .contains_key(&delegate.sub_unification_table_root_var(vid)) + { + hidden_types_of_opaques_in_body.push(bound.fold_with(&mut rest_canonicalizer)); + false + } else { + true + } + }); + if hidden_types_of_opaques_in_body.len() == prev_len { + break; + } + } + + let hidden_types_of_opaques_in_body = + delegate.cx().mk_opaque_hidden_ty_bounds_in_body(&hidden_types_of_opaques_in_body); + + let value = + QueryInput { goal, predefined_opaques_in_body, hidden_types_of_opaques_in_body }; debug_assert!(!value.has_infer(), "unexpected infer in {value:?}"); debug_assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index 655ab64145db5..03342e238912b 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -27,7 +27,8 @@ use tracing::instrument; use crate::delegate::SolverDelegate; use crate::solve::{ CanonicalResponse, Certainty, ExternalConstraintsData, ExternalRegionConstraints, Goal, - NestedNormalizationGoals, QueryInput, Response, VisibleForLeakCheck, inspect, + NestedNormalizationGoals, QueryInput, RawExternalConstraintsData, Response, + VisibleForLeakCheck, inspect, }; pub mod canonicalizer; @@ -56,6 +57,7 @@ pub(super) fn canonicalize_goal( delegate: &D, goal: Goal, opaque_types: &[(ty::OpaqueTypeKey, I::Ty)], + opaque_hidden_ty_bounds: &[(I::Ty, ty::OpaqueHiddenTyBound)], typing_mode: TypingMode, ) -> (ThinVec, I::CanonicalInput) where @@ -67,6 +69,9 @@ where QueryInput { goal, predefined_opaques_in_body: delegate.cx().mk_predefined_opaques_in_body(opaque_types), + hidden_types_of_opaques_in_body: delegate + .cx() + .mk_opaque_hidden_ty_bounds_in_body(opaque_hidden_ty_bounds), }, ); @@ -77,17 +82,24 @@ where (orig_values, query_input) } -pub(super) fn canonicalize_response( +pub(super) fn canonicalize_response( delegate: &D, max_input_universe: ty::UniverseIndex, - value: T, -) -> ty::Canonical + var_values: CanonicalVarValues, + certainty: Certainty, + external_constraints: RawExternalConstraintsData, +) -> ty::Canonical> where D: SolverDelegate, I: Interner, - T: TypeFoldable, { - Canonicalizer::canonicalize_response(delegate, max_input_universe, value) + Canonicalizer::canonicalize_query_response( + delegate, + max_input_universe, + var_values, + certainty, + external_constraints, + ) } /// After calling a canonical query, we apply the constraints returned @@ -116,8 +128,12 @@ where unify_query_var_values(delegate, &original_values, var_values, span); - let ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } = - &*external_constraints; + let ExternalConstraintsData { + region_constraints, + opaque_types, + opaque_hidden_ty_bounds, + normalization_nested_goals, + } = &*external_constraints; match region_constraints { ExternalRegionConstraints::Old(r) => register_region_constraints( @@ -137,7 +153,8 @@ where delegate.register_solver_region_constraint(r.clone(), span) } }; - register_new_opaque_types(delegate, opaque_types, span); + register_new_opaque_types(delegate, opaque_types.as_slice(), span); + delegate.add_opaque_hidden_ty_bounds_in_storage(opaque_hidden_ty_bounds.as_slice()); (normalization_nested_goals.clone(), certainty) } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index ae538441499e0..1ef3ec6af2a45 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -14,9 +14,9 @@ use rustc_type_ir::solve::{ RerunNonErased, RerunReason, RerunResultExt, SizedTraitKind, StalledOnCoroutines, }; use rustc_type_ir::{ - self as ty, AliasTy, Const, Interner, MayBeErased, Region, TypeFlags, TypeFoldable, TypeFolder, - TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, - TypingMode, Unnormalized, Upcast, elaborate, + self as ty, AliasTy, Const, Interner, MayBeErased, Region, TypeFlags, TypeFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Unnormalized, + Upcast, elaborate, }; use tracing::{debug, instrument}; @@ -431,6 +431,25 @@ where ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolutionOrRerunNonErased>; + + fn consider_hidden_types_of_opaques_bound_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + bound: ty::OpaqueHiddenTyBound, + ) -> Result, NoSolutionOrRerunNonErased> { + let assumption = bound.instantiate(ecx.cx(), goal.predicate.self_ty()); + Self::probe_and_match_goal_against_assumption( + ecx, + CandidateSource::AliasBound(AliasBoundKind::SelfBounds), + goal, + assumption, + |ecx| { + // We want to reprove this goal once we've inferred the + // hidden type, so we force the certainty to `Maybe`. + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + }, + ) + } } /// Allows callers of `assemble_and_evaluate_candidates` to choose whether to limit @@ -1129,8 +1148,10 @@ where ) -> Result<(), RerunNonErased> { let self_ty = goal.predicate.self_ty(); // We only use this hack during HIR typeck. - let opaque_types = match self.typing_mode() { - TypingMode::Typeck { .. } => self.opaques_with_sub_unified_hidden_type(self_ty), + let hidden_types_of_opaques = match self.typing_mode() { + TypingMode::Typeck { .. } => { + self.hidden_types_of_opaques_modulo_sub_unification(self_ty) + } TypingMode::Coherence | TypingMode::PostTypeckUntilBorrowck { .. } | TypingMode::PostBorrowck { .. } @@ -1144,62 +1165,24 @@ where } }; - if opaque_types.is_empty() { + if hidden_types_of_opaques.is_empty() { candidates.extend(self.forced_ambiguity(MaybeInfo::AMBIGUOUS)); return Ok(()); } - for &opaque_ty in &opaque_types { - debug!("self ty is sub unified with {opaque_ty:?}"); - - struct ReplaceOpaque { - cx: I, - opaque_ty: ty::OpaqueAliasTy, - self_ty: I::Ty, - } - impl TypeFolder for ReplaceOpaque { - fn cx(&self) -> I { - self.cx - } - fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { - if let ty::Alias(is_rigid, alias_ty) = ty.kind() - && let Some(opaque_ty) = alias_ty.try_to_opaque() - { - if opaque_ty == self.opaque_ty { - debug_assert_eq!(is_rigid, ty::IsRigid::No); - return self.self_ty; - } - } - ty.super_fold_with(self) - } - } + for (hidden_ty, bounds) in hidden_types_of_opaques { + debug!("self ty is sub unified with {hidden_ty:?}"); - // We look at all item-bounds of the opaque, replacing the - // opaque with the current self type before considering - // them as a candidate. Imagine we've got `?x: Trait` - // and `?x` has been sub-unified with the hidden type of - // `impl Trait`, We take the item bound `opaque: Trait` + // We look at all item-bounds of the hidden types, replacing the + // instantiating the self type of the bound with the current self + // type before considering them as a candidate. Imagine we've got + // `?x: Trait` and `?x` has been sub-unified with the hidden + // type of `impl Trait`, We take the item bound `opaque: Trait` // and replace all occurrences of `opaque` with `?x`. This results // in a `?x: Trait` alias-bound candidate. - for item_bound in self - .cx() - .item_self_bounds(opaque_ty.kind.into()) - .iter_instantiated(self.cx(), opaque_ty.args) - .map(Unnormalized::skip_norm_wip) - { - let assumption = - item_bound.fold_with(&mut ReplaceOpaque { cx: self.cx(), opaque_ty, self_ty }); - candidates.extend(G::probe_and_match_goal_against_assumption( - self, - CandidateSource::AliasBound(AliasBoundKind::SelfBounds), - goal, - assumption, - |ecx| { - // We want to reprove this goal once we've inferred the - // hidden type, so we force the certainty to `Maybe`. - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - }, - )); + for bound in bounds { + candidates + .extend(G::consider_hidden_types_of_opaques_bound_candidate(self, goal, bound)); } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/fast_path.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/fast_path.rs index 988850bc64c5b..26941e3a255cd 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/fast_path.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/fast_path.rs @@ -78,13 +78,14 @@ where GoalStalledOnOpaques::No => {} &GoalStalledOnOpaques::Yes { num_opaques_in_storage, + num_hidden_ty_bounds_in_storage, ref previously_succeeded_in_erased, } => { // If any opaques changed in the opaque type storage, // rerunning might make progress so we should rerun. if delegate .opaque_types_storage_num_entries() - .needs_reevaluation(num_opaques_in_storage) + .needs_reevaluation(num_opaques_in_storage, num_hidden_ty_bounds_in_storage) { // Unless this goal previously succeeded in erased mode. // If the stalled goal successfully evaluated while erasing opaque types, diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index c841845392429..eea65a982583e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -24,7 +24,7 @@ use rustc_type_ir::{ use thin_vec::ThinVec; use tracing::{Level, debug, instrument, trace, warn}; -use super::has_only_region_constraints; +use super::{RawExternalConstraintsData, has_only_region_constraints_or_opaque_hidden_ty_bounds}; use crate::canonical::{ canonicalize_goal, canonicalize_response, instantiate_and_apply_query_response, response_no_constraints_raw, @@ -41,10 +41,9 @@ use crate::solve::fast_path::compute_goal_fast_path_cold; use crate::solve::search_graph::SearchGraph; use crate::solve::ty::may_use_unstable_feature; use crate::solve::{ - CanonicalResponse, Certainty, ExternalConstraintsData, FIXPOINT_STEP_LIMIT, Goal, - GoalEvaluation, GoalSource, GoalStalledOn, GoalStalledOnOpaques, HasChanged, MaybeCause, - NestedNormalizationGoals, NoSolution, QueryInput, QueryResult, Response, SucceededInErased, - VisibleForLeakCheck, inspect, + CanonicalResponse, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluation, GoalSource, + GoalStalledOn, GoalStalledOnOpaques, HasChanged, MaybeCause, NestedNormalizationGoals, + NoSolution, QueryInput, QueryResult, SucceededInErased, VisibleForLeakCheck, inspect, }; pub mod fast_path; @@ -545,6 +544,10 @@ where } } + delegate.add_opaque_hidden_ty_bounds_in_storage( + input.hidden_types_of_opaques_in_body.as_slice(), + ); + let initial_opaque_types_storage_num_entries = delegate.opaque_types_storage_num_entries(); if cfg!(debug_assertions) && delegate.typing_mode_raw().is_erased_not_coherence() { assert!(delegate.clone_opaque_types_lookup_table().is_empty()); @@ -767,18 +770,21 @@ where // so we only canonicalize the lookup table and ignore // duplicate entries. let opaque_types = self.delegate.clone_opaque_types_lookup_table(); + let hidden_types_of_opaques = self.delegate.clone_opaque_hidden_ty_bounds(); - let (goal, opaque_types) = - self.delegate.deeply_resolve_via_unification_table((goal, opaque_types)); + let (goal, opaque_types, opaque_hidden_ty_bounds) = self + .delegate + .deeply_resolve_via_unification_table((goal, opaque_types, hidden_types_of_opaques)); let typing_mode = self.typing_mode(); let step_kind = self.step_kind_for_source(source); let tracing_span = tracing::span!( Level::DEBUG, "evaluate_goal_raw in typing mode", - "{:?} opaques={:?}", + "{:?} opaques={:?}, opaque_hidden_ty_bounds={:?}", typing_mode, - opaque_types + opaque_types, + opaque_hidden_ty_bounds, ) .entered(); @@ -826,6 +832,7 @@ where self.delegate, goal, &[], + &[], TypingMode::ErasedNotCoherence(MayBeErased), ); @@ -861,8 +868,13 @@ where } } - let (orig_values, canonical_goal) = - canonicalize_goal(self.delegate, goal, &opaque_types, typing_mode); + let (orig_values, canonical_goal) = canonicalize_goal( + self.delegate, + goal, + &opaque_types, + &opaque_hidden_ty_bounds, + typing_mode, + ); let (canonical_result, accessed_opaques) = self.evaluate_in_search_graph(canonical_goal, step_kind); @@ -888,8 +900,7 @@ where drop(tracing_span); - let has_changed = - if !has_only_region_constraints(response) { HasChanged::Yes } else { HasChanged::No }; + let before_instantiate_response = self.delegate.num_opaque_hidden_ty_bounds(); let (normalization_nested_goals, certainty) = instantiate_and_apply_query_response( self.delegate, @@ -898,6 +909,19 @@ where self.origin_span, ); + // `opaque_hidden_ty_bounds` may vary modulo regions which might be able to be unified in + // the caller in the end. So, instead of the response has any, check whether the storage + // entries actually changed. + // + // See `tests/ui/traits/next-solver/opaques/non-defining-use-stall-on-no-actual-change-in-the-caller.rs` + let has_changed = if !has_only_region_constraints_or_opaque_hidden_ty_bounds(response) + || self.delegate.num_opaque_hidden_ty_bounds() != before_instantiate_response + { + HasChanged::Yes + } else { + HasChanged::No + }; + // FIXME: We previously had an assert here that checked that recomputing // a goal after applying its constraints did not change its response. // @@ -965,16 +989,18 @@ where }) .collect(); + let num_opaques_in_storage = + canonical_goal.canonical.value.predefined_opaques_in_body.len(); + let num_hidden_ty_bounds_in_storage = + canonical_goal.canonical.value.hidden_types_of_opaques_in_body.len(); + GoalStalledOn { stalled_vars, sub_roots, stalled_maybe_info: maybe_info, opaques: GoalStalledOnOpaques::Yes { - num_opaques_in_storage: canonical_goal - .canonical - .value - .predefined_opaques_in_body - .len(), + num_opaques_in_storage, + num_hidden_ty_bounds_in_storage, previously_succeeded_in_erased, }, } @@ -1488,6 +1514,20 @@ where self.delegate.register_hidden_type_in_storage(opaque_type_key, hidden_ty, self.origin_span) } + pub(super) fn add_hidden_type_of_opaque_in_storage( + &self, + hidden_ty: I::Ty, + bounds: impl IntoIterator>, + ) { + self.delegate.add_hidden_type_of_opaque_in_storage(hidden_ty, bounds); + } + pub(super) fn add_opaque_hidden_ty_bounds_in_storage( + &self, + bounds: &[(I::Ty, ty::OpaqueHiddenTyBound)], + ) { + self.delegate.add_opaque_hidden_ty_bounds_in_storage(bounds); + } + pub(super) fn add_item_bounds_for_hidden_type( &mut self, opaque_def_id: I::OpaqueTyId, @@ -1600,12 +1640,12 @@ where Ok(may_use_unstable_feature(&**self.delegate, param_env, symbol)) } - pub(crate) fn opaques_with_sub_unified_hidden_type( + pub(crate) fn hidden_types_of_opaques_modulo_sub_unification( &self, self_ty: I::Ty, - ) -> Vec> { + ) -> Vec<(I::Ty, Vec>)> { if let ty::Infer(ty::TyVar(vid)) = self_ty.kind() { - self.delegate.opaques_with_sub_unified_hidden_type(vid) + self.delegate.hidden_types_of_opaques_modulo_sub_unification(vid) } else { vec![] } @@ -1721,14 +1761,14 @@ where filter_irrelevant_region_constraints(self.delegate, &var_values, &mut external_constraints); + external_constraints.opaque_hidden_ty_bounds.retain(|(hidden_ty, _)| hidden_ty.is_ty_var()); + let canonical = canonicalize_response( self.delegate, self.max_input_universe, - Response { - var_values, - certainty, - external_constraints: self.cx().mk_external_constraints(external_constraints), - }, + var_values, + certainty, + external_constraints, ); Ok(canonical) @@ -1762,7 +1802,7 @@ where &self, certainty: Certainty, normalization_nested_goals: NestedNormalizationGoals, - ) -> ExternalConstraintsData { + ) -> RawExternalConstraintsData { // We only return region constraints once the certainty is `Yes`. This // is necessary as we may drop nested goals on ambiguity, which may result // in unconstrained inference variables in the region constraints. It also @@ -1790,15 +1830,21 @@ where // // Constraints for any existing opaque types are already tracked by changes // to the `var_values`. - let opaque_types = self - .delegate - .clone_opaque_types_added_since(self.initial_opaque_types_storage_num_entries); + let initial_entries = self.initial_opaque_types_storage_num_entries; + let opaque_types = self.delegate.clone_opaque_types_added_since(initial_entries); + let opaque_hidden_ty_bounds = + self.delegate.clone_opaque_hidden_ty_bounds_added_since(initial_entries); if self.typing_mode().is_erased_not_coherence() { - assert!(opaque_types.is_empty()); + assert!(opaque_types.is_empty() && opaque_hidden_ty_bounds.is_empty()); } - ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } + RawExternalConstraintsData { + region_constraints, + opaque_types, + opaque_hidden_ty_bounds, + normalization_nested_goals, + } } pub(super) fn normalize>( @@ -1839,7 +1885,7 @@ where fn filter_irrelevant_region_constraints( delegate: &D, var_values: &CanonicalVarValues, - external_constraints: &mut ExternalConstraintsData, + external_constraints: &mut RawExternalConstraintsData, ) where D: SolverDelegate, I: Interner, @@ -1875,8 +1921,12 @@ fn filter_irrelevant_region_constraints( } } - let ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } = - external_constraints; + let RawExternalConstraintsData { + region_constraints, + opaque_types, + opaque_hidden_ty_bounds, + normalization_nested_goals, + } = external_constraints; // If we have a constraint like `'re: '?1`, where '?1 can name 're and '?1 appears // only on the RHS of region constraints, then this kind of constraint is also trivial, @@ -1891,6 +1941,7 @@ fn filter_irrelevant_region_constraints( // because we skip the RHS of outlives constraints, and `TypeVisitor` doesn't // have a method we can easily override in order to do this. opaque_types.visit_with(&mut vis); + opaque_hidden_ty_bounds.visit_with(&mut vis); normalization_nested_goals.visit_with(&mut vis); for (constraint, _) in r.iter() { match constraint { @@ -2046,11 +2097,18 @@ pub(super) fn evaluate_root_goal_for_proof_tree, root_depth: usize, ) -> (Result, NoSolution>, inspect::GoalEvaluation) { let opaque_types = delegate.clone_opaque_types_lookup_table(); - let (goal, opaque_types) = delegate.deeply_resolve_via_unification_table((goal, opaque_types)); + let opaque_hidden_ty_bounds = delegate.clone_opaque_hidden_ty_bounds(); + let (goal, opaque_types, opaque_hidden_ty_bounds) = delegate + .deeply_resolve_via_unification_table((goal, opaque_types, opaque_hidden_ty_bounds)); let typing_mode = delegate.typing_mode_raw().assert_not_erased(); - let (orig_values, canonical_goal) = - canonicalize_goal(delegate, goal, &opaque_types, typing_mode.into()); + let (orig_values, canonical_goal) = canonicalize_goal( + delegate, + goal, + &opaque_types, + &opaque_hidden_ty_bounds, + typing_mode.into(), + ); let (canonical_result, final_revision, required_depth) = delegate.cx().evaluate_root_goal_for_proof_tree_raw(canonical_goal, root_depth); diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index dddc78373b1b5..4272da179b712 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -24,6 +24,7 @@ use derive_where::derive_where; use rustc_type_ir::inherent::*; pub use rustc_type_ir::solve::*; use rustc_type_ir::{self as ty, Const, Interner, Region, TypeVisitableExt}; +use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use tracing::instrument; pub use self::eval_ctxt::{ @@ -60,11 +61,13 @@ fn has_no_inference_or_external_constraints( let ExternalConstraintsData { ref region_constraints, ref opaque_types, + ref opaque_hidden_ty_bounds, ref normalization_nested_goals, } = *response.value.external_constraints; response.value.var_values.is_identity() && region_constraints.is_empty() && opaque_types.is_empty() + && opaque_hidden_ty_bounds.is_empty() && normalization_nested_goals.is_empty() } @@ -72,6 +75,22 @@ fn has_only_region_constraints(response: ty::Canonical( + response: ty::Canonical>, +) -> bool { + let ExternalConstraintsData { + region_constraints: _, + ref opaque_types, + opaque_hidden_ty_bounds: _, ref normalization_nested_goals, } = *response.value.external_constraints; response.value.var_values.is_identity_modulo_regions() @@ -440,3 +459,12 @@ pub struct GoalEvaluation { /// before rerunning it. pub stalled_on: Option>, } + +#[derive_where(Clone, Debug; I: Interner)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +pub struct RawExternalConstraintsData { + pub region_constraints: ExternalRegionConstraints, + pub opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, + pub opaque_hidden_ty_bounds: Vec<(I::Ty, ty::OpaqueHiddenTyBound)>, + pub normalization_nested_goals: NestedNormalizationGoals, +} diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs index 388b334ccf618..5408ce00c6930 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs @@ -4,8 +4,8 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverProjectionLangItem, SolverTraitLangItem}; use rustc_type_ir::solve::{ - FetchEligibleAssocItemResponse, NoSolutionOrRerunNonErased, QueryResultOrRerunNonErased, - RerunNonErased, RerunReason, RerunResultExt, + AliasBoundKind, FetchEligibleAssocItemResponse, NoSolutionOrRerunNonErased, + QueryResultOrRerunNonErased, RerunNonErased, RerunReason, RerunResultExt, }; use rustc_type_ir::{ self as ty, Const, FieldInfo, Interner, NormalizesTo, PredicateKind, Region, Unnormalized, @@ -1087,6 +1087,48 @@ where ) -> Result, NoSolutionOrRerunNonErased> { unreachable!("try_as_dyn helper trait doesn't have assoc types") } + + fn consider_hidden_types_of_opaques_bound_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + bound: ty::OpaqueHiddenTyBound, + ) -> Result, NoSolutionOrRerunNonErased> { + let NormalizesTo { alias, term } = goal.predicate; + let cx = ecx.cx(); + let assumption = bound.instantiate(cx, alias.self_ty()); + Self::probe_and_match_goal_against_assumption( + ecx, + CandidateSource::AliasBound(AliasBoundKind::SelfBounds), + goal, + assumption, + |ecx| { + // Add self bounds for `::Assoc`. Those bounds should be added to + // storage if and only if `` is proven by + // `ty::OpaqueHiddenTyBound` of an opaque (or another assoc ty on it), otherwise + // it might make blaket impl candidate inapplicable. + // See `tests/ui/impl-trait/non-defining-uses/use-blanket-impl.rs` for such case. + if ecx.typing_mode().should_add_hidden_types_of_opaques() + && let ty::AliasTermKind::ProjectionTy { def_id } = alias.kind + { + ecx.add_hidden_type_of_opaque_in_storage( + term.expect_ty(), + ty::OpaqueHiddenTyBound::iter_item_self_bounds_for_hidden_ty( + cx, + ty::AliasTy::new_from_args( + cx, + ty::AliasTyKind::Projection { def_id }, + alias.args, + ), + ), + ); + } + + // We want to reprove this goal once we've inferred the + // hidden type, so we force the certainty to `Maybe`. + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + }, + ) + } } impl EvalCtxt<'_, D> diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs index 9d6b8875071ba..3ec626946e8c3 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs @@ -3,6 +3,7 @@ mod free_alias; mod inherent; mod opaque_types; +use rustc_type_ir::inherent::*; use rustc_type_ir::solve::QueryResultOrRerunNonErased; use rustc_type_ir::{self as ty, Interner, ProjectionClause}; use tracing::{instrument, trace}; @@ -50,6 +51,27 @@ where let normalizes_to = goal.with(self.cx(), ty::NormalizesTo { alias, term: unconstrained_term }); + // For the reason why we need this hack, see the comments on + // [`ty::OpaqueHiddenTyBound::opt_unmentioned_projection_bound`]. + // We register this hacky bound as lazy as possible, at here instead of at the normalization + // of the initial hidden type. That's because we might acquire the originally unmentioned + // bound while proving other goals and if so we might fail the evaluation due to having + // multiple candidates due to this hacky bound. + if self.typing_mode().should_add_hidden_types_of_opaques() + && unconstrained_term.as_type().is_some() + && alias.self_ty().is_ty_var() + { + let hidden_bounds = + self.hidden_types_of_opaques_modulo_sub_unification(alias.self_ty()); + if let Some(unmentioned) = ty::OpaqueHiddenTyBound::opt_unmentioned_projection_bound( + self.cx(), + hidden_bounds.iter().flat_map(|(_, bounds)| bounds).copied(), + goal.predicate, + ) { + self.add_opaque_hidden_ty_bounds_in_storage(&[(alias.self_ty(), unmentioned)]); + } + } + // We don't want candidate selection when normalizing associated terms to be impacted by // the expected term. Normalization should behave like a function of just the alias being // normalized. Because of this, we use an internal `NormalizesTo` goal for which the diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs index 2f56056449779..68653e9bb83bd 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs @@ -117,6 +117,19 @@ where goal.param_env, expected, )?; + if self.typing_mode().should_add_hidden_types_of_opaques() { + self.add_hidden_type_of_opaque_in_storage( + expected, + ty::OpaqueHiddenTyBound::iter_item_self_bounds_for_hidden_ty( + cx, + ty::AliasTy::new_from_args( + cx, + ty::AliasTyKind::Opaque { def_id: def_id.into() }, + normalized_args, + ), + ), + ); + } self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) .map_err(Into::into) } diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 19a09e99c7d64..b50127af7311b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -1314,6 +1314,7 @@ where let ExternalConstraintsData { region_constraints: _, ref opaque_types, + ref opaque_hidden_ty_bounds, ref normalization_nested_goals, } = *candidate.result.value.external_constraints; debug_assert!(normalization_nested_goals.is_empty()); @@ -1322,7 +1323,7 @@ where // inference state. This is safe after typeck, where hidden types are already // fixed and only regions are inferred, but not during typeck while hidden // types may still contain inference variables. - if !opaque_types.is_empty() { + if !opaque_types.is_empty() || !opaque_hidden_ty_bounds.is_empty() { let typing_mode = self.typing_mode(); match typing_mode { diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index e1043d53fa6fc..0102edf94d170 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -89,6 +89,7 @@ fn goal_stalled_on_args_or_nonempty_opaques<'tcx>( stalled_maybe_info: MaybeInfo::AMBIGUOUS, opaques: GoalStalledOnOpaques::Yes { num_opaques_in_storage: 0, + num_hidden_ty_bounds_in_storage: 0, // This function should only be called when not in erased mode, // otherwise this is wrong. The `compute_goal_fast_path` does this // through `known_no_opaque_types_in_storage` diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 7d3c0a4a6c1f1..1f7059b4443ed 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -422,6 +422,6 @@ mod size_asserts { // `memcpy` for moving elements of `PendingObligations`. Then #160479 greatly reduced the // number of `memcpy` operations in `try_evaluate_obligations`. So the size of this pair is // much less important than it was, but still shouldn't be changed without some thought. - static_assert_size!((PredicateObligation<'_>, Option>>), 104); + static_assert_size!((PredicateObligation<'_>, Option>>), 112); // tidy-alphabetical-end } diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index d50f6521441d5..64473f1856437 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -275,6 +275,23 @@ impl TypingMode { | TypingMode::Codegen => false, } } + + /// This is `true` for `Typeck` and `false` otherwise as we take into account the + /// item self bounds for `hidden_types_of_opaques` for that `TypingMode` only. + /// + /// See also the documentation on [`TypingMode`] about exhaustive matching. + pub fn should_add_hidden_types_of_opaques(&self) -> bool { + match self { + TypingMode::Typeck { .. } => true, + TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::Coherence + | TypingMode::PostBorrowck { .. } + | TypingMode::Reflection + | TypingMode::PostAnalysis + | TypingMode::Codegen + | TypingMode::ErasedNotCoherence(_) => false, + } + } } impl TypingMode { @@ -546,20 +563,25 @@ pub trait InferCtxtLike: Sized { type OpaqueTypeStorageEntries: OpaqueTypeStorageEntries; fn opaque_types_storage_num_entries(&self) -> Self::OpaqueTypeStorageEntries; + fn num_opaque_hidden_ty_bounds(&self) -> usize; fn clone_opaque_types_lookup_table( &self, ) -> Vec<(ty::OpaqueTypeKey, ::Ty)>; - fn clone_duplicate_opaque_types( + fn clone_opaque_hidden_ty_bounds( &self, - ) -> Vec<(ty::OpaqueTypeKey, ::Ty)>; + ) -> Vec<(::Ty, ty::OpaqueHiddenTyBound)>; fn clone_opaque_types_added_since( &self, prev_entries: Self::OpaqueTypeStorageEntries, ) -> Vec<(ty::OpaqueTypeKey, ::Ty)>; - fn opaques_with_sub_unified_hidden_type( + fn clone_opaque_hidden_ty_bounds_added_since( + &self, + prev_entries: Self::OpaqueTypeStorageEntries, + ) -> Vec<(::Ty, ty::OpaqueHiddenTyBound)>; + fn hidden_types_of_opaques_modulo_sub_unification( &self, - ty: TyVid, - ) -> Vec>; + ty_vid: TyVid, + ) -> Vec<(::Ty, Vec>)>; fn register_hidden_type_in_storage( &self, @@ -573,6 +595,15 @@ pub trait InferCtxtLike: Sized { hidden_ty: ::Ty, span: ::Span, ); + fn add_hidden_type_of_opaque_in_storage( + &self, + hidden_ty: ::Ty, + bounds: impl IntoIterator>, + ); + fn add_opaque_hidden_ty_bounds_in_storage( + &self, + bounds: &[(::Ty, ty::OpaqueHiddenTyBound)], + ); fn reset_opaque_types(&self); diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 28b733a865358..d66036b90c383 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -640,11 +640,11 @@ pub trait Span: Copy + Debug + Hash + Eq + TypeFoldable { } #[rust_analyzer::prefer_underscore_import] -pub trait OpaqueTypeStorageEntries: Debug + Copy + Default { +pub trait OpaqueTypeStorageEntries: Debug + Clone + Copy + Default + PartialEq + Eq { /// Whether the number of opaques has changed in a way that necessitates /// reevaluating a goal. For now, this is only when the number of non-duplicated - /// entries changed. - fn needs_reevaluation(self, canonicalized: usize) -> bool; + /// entries and bounds for hidden types of opaques changed. + fn needs_reevaluation(self, opaques: usize, hidden_ty_bounds: usize) -> bool; } pub trait BoundVarKinds: diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index e3bf97dfebd26..244d0ebf8210e 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -129,6 +129,17 @@ pub trait Interner: data: &[(ty::OpaqueTypeKey, Self::Ty)], ) -> Self::PredefinedOpaques; + type OpaqueHiddenTyBounds: Copy + + Debug + + Hash + + Eq + + TypeFoldable + + SliceLike)>; + fn mk_opaque_hidden_ty_bounds_in_body( + self, + data: &[(Self::Ty, ty::OpaqueHiddenTyBound)], + ) -> Self::OpaqueHiddenTyBounds; + type LocalDefIds: Copy + Debug + Hash diff --git a/compiler/rustc_type_ir/src/opaque_ty.rs b/compiler/rustc_type_ir/src/opaque_ty.rs index 51b3860ba1ff1..a2d6a09ede5e8 100644 --- a/compiler/rustc_type_ir/src/opaque_ty.rs +++ b/compiler/rustc_type_ir/src/opaque_ty.rs @@ -1,10 +1,14 @@ use derive_where::derive_where; +use rustc_index::Idx; #[cfg(feature = "nightly")] use rustc_macros::{Decodable_NoContext, Encodable_NoContext, StableHash_NoContext}; use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic}; use crate::inherent::*; -use crate::{self as ty, Interner, Region}; +use crate::{ + self as ty, Binder, Interner, Region, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitableExt, Upcast, +}; #[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)] @@ -48,3 +52,208 @@ impl OpaqueTypeKey { Self { def_id, args } } } + +/// An item self bound for a hidden type(either an opaque or projection onto another hidden type). +/// This is meant to be instantiated inside the solver into an assumption for a goal with the goal's +/// self ty to support non-defining usages. +#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] +#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, StableHash_NoContext) +)] +pub struct OpaqueHiddenTyBound { + bound: Binder, +} + +impl Eq for OpaqueHiddenTyBound {} + +impl OpaqueHiddenTyBound { + /// Iterate through the item self bounds of a hidden type for either an opaque + /// or a projection onto another hidden ty. + pub fn iter_item_self_bounds_for_hidden_ty( + cx: I, + alias: ty::AliasTy, + ) -> impl Iterator { + let def_id = match alias.kind { + ty::AliasTyKind::Projection { def_id } => def_id.into(), + ty::AliasTyKind::Opaque { def_id } => def_id.into(), + ty::AliasTyKind::Inherent { .. } | ty::AliasTyKind::Free { .. } => unreachable!( + "Opaque hidden type should be either an opaque type or projection on another hidden type" + ), + }; + + let args = alias.args; + let alias = I::Ty::new_alias(cx, ty::IsRigid::No, alias); + cx.item_self_bounds(def_id).iter_instantiated(cx, args).map(move |bound| { + let bound = Binder::bind_with_vars( + bound + .skip_normalization() + .fold_with(&mut ReplaceSelfTyWithAnonBound::new(cx, alias)), + I::BoundVarKinds::from_vars(cx, [ty::BoundVariableKind::Ty(ty::BoundTyKind::Anon)]), + ); + OpaqueHiddenTyBound { bound } + }) + } + + /// If the given `projection` is not mentioned among the given `existing_bounds`, + /// create one for it. + /// + /// This is needed to support the non-defining usages like in the following case: + /// + /// ```no_run + /// fn argument_types() -> impl IntoIterator { + /// argument_types().into_iter().collect::>() + /// // ^ ^ + /// // | | + /// // `{opaque}` | + /// // `<{opaque} as IntoIterator>::IntoIter` + /// } + /// ``` + /// + /// We need to prove `<{opaque} as IntoIterator>::IntoIter: Iterator` to select the + /// method `collect()` on it. But as the given bounds in the scope don't mention the + /// assoc type `IntoIterator::IntoIter` at all, we can't assemble a candidate for + /// that trait goal. So, we have manually conjure a bound for such unmentioned + /// projections. + pub fn opt_unmentioned_projection_bound( + cx: I, + existing_bounds: impl IntoIterator, + proj: ty::ProjectionClause, + ) -> Option { + let trait_def_id = proj.trait_def_id(cx); + let mut mentions_trait = false; + for bound in existing_bounds.into_iter() { + if bound + .bound + .skip_binder() + .as_projection_clause() + .is_some_and(|b| b.item_def_id() == proj.def_id()) + { + // Mentioned already + return None; + } + + if bound + .bound + .skip_binder() + .as_trait_clause() + .is_some_and(|b| b.def_id() == trait_def_id) + { + mentions_trait = true; + } + } + + if !mentions_trait { + return None; + } + + let bound: I::Clause = proj.upcast(cx); + let bound = Binder::bind_with_vars( + bound.fold_with(&mut ReplaceSelfTyWithAnonBound::new(cx, proj.self_ty())), + I::BoundVarKinds::from_vars(cx, [ty::BoundVariableKind::Ty(ty::BoundTyKind::Anon)]), + ); + Some(OpaqueHiddenTyBound { bound }) + } + + pub fn instantiate(self, cx: I, self_ty: I::Ty) -> I::Clause { + let OpaqueHiddenTyBound { bound } = self; + + debug_assert_eq!( + bound.bound_vars().as_slice(), + &[ty::BoundVariableKind::Ty(ty::BoundTyKind::Anon)] + ); + debug_assert!(bound.skip_binder().has_escaping_bound_vars()); + + let bound = + self.bound.skip_binder().fold_with(&mut ReplaceAnonBoundWithSelfTy::new(cx, self_ty)); + debug_assert!(!bound.has_escaping_bound_vars()); + + bound + } +} + +struct ReplaceSelfTyWithAnonBound { + cx: I, + self_ty: I::Ty, + debruijn: ty::DebruijnIndex, + bound_var: ty::BoundVar, +} + +impl ReplaceSelfTyWithAnonBound { + fn new(cx: I, self_ty: I::Ty) -> Self { + ReplaceSelfTyWithAnonBound { + cx, + self_ty, + debruijn: ty::INNERMOST, + bound_var: ty::BoundVar::new(0), + } + } +} + +impl TypeFolder for ReplaceSelfTyWithAnonBound { + fn cx(&self) -> I { + self.cx + } + + fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { + if ty == self.self_ty { + I::Ty::new_anon_bound(self.cx, self.debruijn, self.bound_var) + } else { + ty.super_fold_with(self) + } + } + + fn fold_binder(&mut self, t: ty::Binder) -> ty::Binder + where + T: TypeFoldable, + { + self.debruijn.shift_in(1); + let result = t.super_fold_with(self); + self.debruijn.shift_out(1); + result + } +} + +struct ReplaceAnonBoundWithSelfTy { + cx: I, + self_ty: I::Ty, + debruijn: ty::DebruijnIndex, + bound_ty: ty::BoundTy, +} + +impl ReplaceAnonBoundWithSelfTy { + fn new(cx: I, self_ty: I::Ty) -> Self { + ReplaceAnonBoundWithSelfTy { + cx, + self_ty, + debruijn: ty::INNERMOST, + bound_ty: ty::BoundTy { var: ty::BoundVar::new(0), kind: ty::BoundTyKind::Anon }, + } + } +} + +impl TypeFolder for ReplaceAnonBoundWithSelfTy { + fn cx(&self) -> I { + self.cx + } + + fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { + let ty = ty.super_fold_with(self); + if ty::Bound(ty::BoundVarIndexKind::Bound(self.debruijn), self.bound_ty) == ty.kind() { + self.self_ty + } else { + ty + } + } + + fn fold_binder(&mut self, t: ty::Binder) -> ty::Binder + where + T: TypeFoldable, + { + self.debruijn.shift_in(1); + let result = t.super_fold_with(self); + self.debruijn.shift_out(1); + result + } +} diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index c6d88bb6603de..8c5e247b25f70 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -456,6 +456,7 @@ pub enum GoalSource { pub struct QueryInput { pub goal: Goal, pub predefined_opaques_in_body: I::PredefinedOpaques, + pub hidden_types_of_opaques_in_body: I::OpaqueHiddenTyBounds, } impl Eq for QueryInput {} @@ -563,7 +564,7 @@ pub enum ParamEnvSource { pub enum AliasBoundKind { /// Alias bound from the self type of a projection SelfBounds, - // Alias bound having recursed on the self type of a projection + /// Alias bound having recursed on the self type of a projection NonSelfBounds, } @@ -632,7 +633,8 @@ impl ExternalRegionConstraints { #[cfg_attr(feature = "nightly", derive(StableHash_NoContext))] pub struct ExternalConstraintsData { pub region_constraints: ExternalRegionConstraints, - pub opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, + pub opaque_types: I::PredefinedOpaques, + pub opaque_hidden_ty_bounds: I::OpaqueHiddenTyBounds, pub normalization_nested_goals: NestedNormalizationGoals, } @@ -647,7 +649,8 @@ impl ExternalConstraintsData { Self { region_constraints, - opaque_types: vec![], + opaque_types: cx.mk_predefined_opaques_in_body(&[]), + opaque_hidden_ty_bounds: cx.mk_opaque_hidden_ty_bounds_in_body(&[]), normalization_nested_goals: NestedNormalizationGoals::default(), } } @@ -656,10 +659,12 @@ impl ExternalConstraintsData { let ExternalConstraintsData { region_constraints, opaque_types, + opaque_hidden_ty_bounds, normalization_nested_goals, } = self; region_constraints.is_empty() && opaque_types.is_empty() + && opaque_hidden_ty_bounds.is_empty() && normalization_nested_goals.is_empty() } } @@ -1002,6 +1007,7 @@ pub enum GoalStalledOnOpaques { No, Yes { num_opaques_in_storage: usize, + num_hidden_ty_bounds_in_storage: usize, previously_succeeded_in_erased: SucceededInErased, }, } diff --git a/tests/ui/traits/next-solver/opaques/non-defining-use-projection-on-hidden-1.rs b/tests/ui/traits/next-solver/opaques/non-defining-use-projection-on-hidden-1.rs new file mode 100644 index 0000000000000..18208b18f2abd --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/non-defining-use-projection-on-hidden-1.rs @@ -0,0 +1,27 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Regression test for + +#![allow(warnings)] + +fn foo() -> impl IntoIterator { + if false { + let x: Vec<_> = foo().into_iter().collect(); + } + + [1, 2] +} + +// `Flatten: Iterator` is ambiguous. +fn move_forward() -> impl IntoIterator { + std::iter::empty().map(|_: ()| move_forward()).flatten().collect::>() +} + +fn argument_types() -> impl IntoIterator { + argument_types().into_iter().collect::>() +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/opaques/non-defining-use-projection-on-hidden-2.rs b/tests/ui/traits/next-solver/opaques/non-defining-use-projection-on-hidden-2.rs new file mode 100644 index 0000000000000..d3b87eabd837b --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/non-defining-use-projection-on-hidden-2.rs @@ -0,0 +1,46 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Regression test for +// Test whether we can call methods on not-yet defined nested projections on opaques such as +// `<<{opaque}> as Baz>::Assoc as Bar>::Assoc`. + +#![allow(warnings)] + +trait Foo { + fn foo(&self) {} +} + +trait Bar { + type Assoc: Foo; + + fn bar(&self) -> Self::Assoc { + loop {} + } +} + +trait Baz { + type Assoc: Bar; + + fn baz(&self) -> Self::Assoc { + loop {} + } +} + +impl Foo for () {} + +impl Bar for () { + type Assoc = (); +} + +impl Baz for () { + type Assoc = (); +} + +fn heck() -> impl Baz { + heck().baz().bar().foo() +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/opaques/non-defining-use-stall-on-no-actual-change-im-the-caller.rs b/tests/ui/traits/next-solver/opaques/non-defining-use-stall-on-no-actual-change-im-the-caller.rs new file mode 100644 index 0000000000000..6f6803e622c60 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/non-defining-use-stall-on-no-actual-change-im-the-caller.rs @@ -0,0 +1,76 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// This is rather an implementation-detail-related test. +// +// We track self-bounds of opaque-hidden-types in the `InferCtxt` and pass them via both query +// inputs and responses. We try to dedup them per eager resolving and structural equality but they +// don't always work well, especially due to canonicalizations. +// +// Suppose that we have such bound with `'static` lifetime. If we try to normalize that hidden type, +// we get that bound from the query response and is registered into the caller's context. And if we +// try to reevaluate that nested normalization goal again, it is passed into a query input. But as +// `'static` region is canonicalized into a placeholder region, we cannot deduplicate it in the +// callee's side and thus we return the same bound with `'static` region from the previous region +// again. +// +// This pathetic reevaluation never stops and until we hit the recursion limit and end up with an +// overflow. To prevent this, we simply check whether the number of opaque hidden ty bounds has +// actually increased from the evaluation after instantiating the response from the callers side to +// decide evaluation's `has_changed`. + +#![allow(warnings)] + +fn features() -> impl Iterator { + None.into_iter() +} + +trait Foo { + fn foo(&self) {} +} + +trait Qux { + type Assoc: Foo; + + fn qux(&self) -> Self::Assoc { + loop {} + } +} + +trait Bar { + type Assoc: Qux; + + fn bar(&self) -> Self::Assoc { + loop {} + } +} + +trait Baz { + type Assoc: Bar; + + fn baz(&self) -> Self::Assoc { + loop {} + } +} + +impl Foo for &'static () {} + +impl Qux for () { + type Assoc = &'static (); +} + +impl Bar for () { + type Assoc = (); +} + +impl Baz for () { + type Assoc = (); +} + +fn heck() -> impl Baz { + heck().baz().bar().qux().foo() +} + +fn main() {} From d2788d7c325b60346403be39a768e945eb67aae7 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Wed, 16 Sep 2026 16:39:26 +0900 Subject: [PATCH 02/12] Address review feedback --- compiler/rustc_hir_analysis/src/autoderef.rs | 2 +- .../rustc_hir_analysis/src/check/check.rs | 16 ++- compiler/rustc_hir_typeck/src/callee.rs | 2 +- compiler/rustc_hir_typeck/src/method/probe.rs | 32 +++-- compiler/rustc_infer/src/infer/context.rs | 36 ++--- compiler/rustc_infer/src/infer/mod.rs | 21 +-- .../rustc_infer/src/infer/opaque_types/mod.rs | 34 ++--- .../src/infer/opaque_types/table.rs | 132 ++++++++++-------- .../src/infer/snapshot/undo_log.rs | 6 +- compiler/rustc_middle/src/traits/query.rs | 4 +- compiler/rustc_middle/src/traits/solve.rs | 15 +- compiler/rustc_middle/src/ty/context.rs | 19 +-- .../src/ty/context/impl_interner.rs | 10 +- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/opaque_types.rs | 3 +- .../rustc_middle/src/ty/structural_impls.rs | 2 +- .../src/canonical/canonicalizer.rs | 113 ++++++++------- .../src/canonical/mod.rs | 12 +- .../src/solve/assembly/mod.rs | 103 ++++++++++---- .../src/solve/effect_goals.rs | 4 + .../src/solve/eval_ctxt/mod.rs | 91 ++++++------ .../rustc_next_trait_solver/src/solve/mod.rs | 14 +- .../src/solve/normalizes_to.rs | 50 +------ .../src/solve/project_goals/mod.rs | 22 --- .../src/solve/project_goals/opaque_types.rs | 17 ++- .../src/solve/trait_goals.rs | 8 +- compiler/rustc_type_ir/src/infer_ctxt.rs | 32 +++-- compiler/rustc_type_ir/src/inherent.rs | 4 +- compiler/rustc_type_ir/src/interner.rs | 10 +- compiler/rustc_type_ir/src/opaque_ty.rs | 33 +++-- compiler/rustc_type_ir/src/solve/mod.rs | 11 +- ...tall-on-no-actual-change-in-the-caller.rs} | 0 32 files changed, 459 insertions(+), 401 deletions(-) rename tests/ui/traits/next-solver/opaques/{non-defining-use-stall-on-no-actual-change-im-the-caller.rs => non-defining-use-stall-on-no-actual-change-in-the-caller.rs} (100%) diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 2cf86878d1fcf..432eee866f4c8 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -74,7 +74,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { // opaque type and instead return `None` in `fn overloaded_deref_ty` if the // opaque does not have a `Deref` item-bound. if let &ty::Infer(ty::TyVar(vid)) = self.state.cur_ty.kind() - && !self.infcx.has_hidden_types_of_opaques_modulo_sub_unification(vid) + && !self.infcx.is_pseudo_rigid_due_to_opaques_modulo_sub_unification(vid) { return None; } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 1d2e8606487f3..9f8426a3eeb4c 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -429,9 +429,11 @@ fn check_opaque_meets_bounds<'tcx>( let _ = infcx.take_opaque_types(); Ok(()) } else { - let (opaques, hiddens) = infcx.take_opaque_types(); - // We don't track anything on `hidden_types_of_opaques` in the old solver. - assert!(hiddens.is_empty()); + let (opaques, pseudo_rigids) = infcx.take_opaque_types(); + debug_assert!( + pseudo_rigids.is_empty(), + "We don't track anything in `pseudo_rigids_due_to_opaques` with the old solver" + ); // Check that any hidden types found during wf checking match the hidden types that `type_of` sees. for (mut key, mut ty) in opaques { ty.ty = infcx.deeply_resolve_ignoring_regions(ty.ty); @@ -2354,9 +2356,11 @@ pub(super) fn check_coroutine_obligations( } if !tcx.next_trait_solver_globally() { - let (opaques, hiddens) = infcx.take_opaque_types(); - // We don't track anything on `hidden_types_of_opaques` in the old solver. - assert!(hiddens.is_empty()); + let (opaques, pseudo_rigids) = infcx.take_opaque_types(); + debug_assert!( + pseudo_rigids.is_empty(), + "We don't track anything in `pseudo_rigids_due_to_opaques` with the old solver" + ); // Check that any hidden types found when checking these stalled coroutine obligations // are valid. for (key, ty) in opaques { diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 117cf83bbce62..fed5afda80d89 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -336,7 +336,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Infer(ty::TyVar(vid)) => { // If we end up with an inference variable which is not the hidden type of // an opaque, emit an error. - if !self.has_hidden_types_of_opaques_modulo_sub_unification(vid) { + if !self.is_pseudo_rigid_due_to_opaques_modulo_sub_unification(vid) { self.type_must_be_known_at_this_point(autoderef.span(), adjusted_ty); return None; } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 0010e12173661..278067fd56b72 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -418,16 +418,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { ty::List::empty() }; - let opaque_hidden_ty_bounds_in_body = if self.next_trait_solver() { - self.tcx.mk_opaque_hidden_ty_bounds_in_body_from_iter( - self.inner.borrow_mut().opaque_types().iter_opaque_hidden_ty_bounds(), + let pseudo_rigid_due_to_opaques_bounds_in_body = if self.next_trait_solver() { + self.tcx.mk_pseudo_rigid_due_to_opaques_bounds_in_body_from_iter( + self.inner.borrow_mut().opaque_types().iter_pseudo_rigid_due_to_opaques_bounds(), ) } else { ty::List::empty() }; let value = query::MethodAutoderefSteps { predefined_opaques_in_body, - opaque_hidden_ty_bounds_in_body, + pseudo_rigid_due_to_opaques_bounds_in_body, self_ty, }; let query_input = self @@ -446,7 +446,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { infcx.instantiate_canonical(span, &query_input.canonical); let query::MethodAutoderefSteps { predefined_opaques_in_body: _, - opaque_hidden_ty_bounds_in_body: _, + pseudo_rigid_due_to_opaques_bounds_in_body: _, self_ty, } = value; debug!(?self_ty, ?query_input, "probe_op: Mode::Path"); @@ -458,7 +458,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty, prev_opaque_entries, ), - self_ty_is_hidden_ty_of_opaque: false, + self_ty_is_pseudo_rigid_opaques: false, autoderefs: 0, from_unsafe_deref: false, unsize: false, @@ -659,7 +659,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( value: query::MethodAutoderefSteps { predefined_opaques_in_body, - opaque_hidden_ty_bounds_in_body, + pseudo_rigid_due_to_opaques_bounds_in_body, self_ty, }, } = goal; @@ -681,15 +681,17 @@ pub(crate) fn method_autoderef_steps<'tcx>( debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_types_storage`"); } } - infcx.add_opaque_hidden_ty_bounds_in_storage(opaque_hidden_ty_bounds_in_body); + infcx.register_pseudo_rigid_due_to_opaques_in_storage_with_flattened( + pseudo_rigid_due_to_opaques_bounds_in_body, + ); 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 // infer var is not an opaque. - let self_ty_is_hidden_ty_of_opaque = |ty: Ty<'_>| { + let self_ty_is_pseudo_rigid_due_to_opaques = |ty: Ty<'_>| { if let &ty::Infer(ty::TyVar(vid)) = ty.kind() { - infcx.has_hidden_types_of_opaques_modulo_sub_unification(vid) + infcx.is_pseudo_rigid_due_to_opaques_modulo_sub_unification(vid) } else { false } @@ -731,7 +733,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( ty, prev_opaque_entries, ), - self_ty_is_hidden_ty_of_opaque: self_ty_is_hidden_ty_of_opaque(ty), + self_ty_is_pseudo_rigid_opaques: self_ty_is_pseudo_rigid_due_to_opaques(ty), autoderefs: d, from_unsafe_deref: reached_raw_pointer, unsize: false, @@ -755,7 +757,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( ty, prev_opaque_entries, ), - self_ty_is_hidden_ty_of_opaque: self_ty_is_hidden_ty_of_opaque(ty), + self_ty_is_pseudo_rigid_opaques: self_ty_is_pseudo_rigid_due_to_opaques(ty), autoderefs: d, from_unsafe_deref: reached_raw_pointer, unsize: false, @@ -772,7 +774,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( }; let final_ty = autoderef_via_deref.final_ty(); let opt_bad_ty = match final_ty.kind() { - ty::Infer(ty::TyVar(_)) if !self_ty_is_hidden_ty_of_opaque(final_ty) => { + ty::Infer(ty::TyVar(_)) if !self_ty_is_pseudo_rigid_due_to_opaques(final_ty) => { Some(MethodAutoderefBadTy { reached_raw_pointer, ty: infcx.make_query_response_ignoring_pending_obligations( @@ -798,7 +800,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( Ty::new_slice(infcx.tcx, *elem_ty), prev_opaque_entries, ), - self_ty_is_hidden_ty_of_opaque: false, + self_ty_is_pseudo_rigid_opaques: false, autoderefs, // this could be from an unsafe deref if we had // a *mut/const [T; N] @@ -2340,7 +2342,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // Check whether any hidden type of opaque in the autoderef chain have been // constrained. for step in self.steps { - if step.self_ty_is_hidden_ty_of_opaque { + if step.self_ty_is_pseudo_rigid_opaques { debug!(?step.autoderefs, ?step.self_ty, "self_type_is_opaque"); let constrained_opaque = self.probe(|_| { // If we fail to instantiate the self type of this diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 0cadf7c8c8401..0adebe316362d 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -343,14 +343,16 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { fn opaque_types_storage_num_entries(&self) -> OpaqueTypeStorageEntries { self.inner.borrow_mut().opaque_types().num_entries() } - fn num_opaque_hidden_ty_bounds(&self) -> usize { - self.inner.borrow_mut().opaque_types().num_opaque_hidden_ty_bounds() + fn num_pseudo_rigid_due_to_opaques_bounds(&self) -> usize { + self.inner.borrow_mut().opaque_types().num_pseudo_rigid_due_to_opaques_bounds() } fn clone_opaque_types_lookup_table(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { self.inner.borrow_mut().opaque_types().iter_lookup_table().map(|(k, h)| (k, h.ty)).collect() } - fn clone_opaque_hidden_ty_bounds(&self) -> Vec<(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)> { - self.inner.borrow_mut().opaque_types().iter_opaque_hidden_ty_bounds().collect() + fn clone_pseudo_rigid_due_to_opaques_bounds( + &self, + ) -> Vec<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)> { + self.inner.borrow_mut().opaque_types().iter_pseudo_rigid_due_to_opaques_bounds().collect() } fn clone_opaque_types_added_since( &self, @@ -363,21 +365,21 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { .map(|(k, h)| (k, h.ty)) .collect() } - fn clone_opaque_hidden_ty_bounds_added_since( + fn clone_pseudo_rigid_due_to_opaques_bounds_added_since( &self, prev_entries: OpaqueTypeStorageEntries, - ) -> Vec<(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)> { + ) -> Vec<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)> { self.inner .borrow_mut() .opaque_types() - .opaque_hidden_ty_bounds_added_since(prev_entries) + .pseudo_rigid_due_to_opaques_bounds_added_since(prev_entries) .collect() } - fn hidden_types_of_opaques_modulo_sub_unification( + fn pseudo_rigids_due_to_opaques_modulo_sub_unification( &self, ty_vid: ty::TyVid, - ) -> Vec<(Ty<'tcx>, Vec>)> { - self.hidden_types_of_opaques_modulo_sub_unification(ty_vid) + ) -> Vec<(Ty<'tcx>, Vec>)> { + self.pseudo_rigids_due_to_opaques_modulo_self_unification(ty_vid) } fn register_hidden_type_in_storage( @@ -402,18 +404,18 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { .opaque_types() .add_duplicate(opaque_type_key, ty::ProvisionalHiddenType { span, ty: hidden_ty }) } - fn add_hidden_type_of_opaque_in_storage( + fn register_pseudo_rigid_due_to_opaques_in_storage( &self, - hidden_ty: Ty<'tcx>, - bounds: impl IntoIterator>, + pseudo_rigid: Ty<'tcx>, + bounds: impl IntoIterator>, ) { - self.add_hidden_type_of_opaque_in_storage(hidden_ty, bounds); + self.register_pseudo_rigid_due_to_opaques_in_storage(pseudo_rigid, bounds); } - fn add_opaque_hidden_ty_bounds_in_storage( + fn register_pseudo_rigid_due_to_opaques_in_storage_with_flattened( &self, - bounds: &[(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)], + bounds: &[(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)], ) { - self.add_opaque_hidden_ty_bounds_in_storage(bounds); + self.register_pseudo_rigid_due_to_opaques_in_storage_with_flattened(bounds); } fn reset_opaque_types(&self) { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 3b3c19edc7f11..957b29f5b2cd6 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1122,7 +1122,7 @@ impl<'tcx> InferCtxt<'tcx> { &self, ) -> ( Vec<(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)>, - Vec<(Ty<'tcx>, FxIndexSet>)>, + Vec<(Ty<'tcx>, FxIndexSet>)>, ) { let mut inner = self.inner.borrow_mut(); let (opaques, hiddens) = inner.opaque_type_storage.take_opaque_types(); @@ -1134,7 +1134,10 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().opaque_type_storage.iter_opaque_types().collect() } - pub fn has_hidden_types_of_opaques_modulo_sub_unification(&self, ty_vid: TyVid) -> bool { + /// In the next solver, we normalize alias types by replacing them with infer vars and + /// registering/evaluating projection goals + /// They often but when we are in the defining scope of an opaque type and we haven't fully + pub fn is_pseudo_rigid_due_to_opaques_modulo_sub_unification(&self, ty_vid: TyVid) -> bool { if !self.next_trait_solver() { return false; } @@ -1142,7 +1145,7 @@ impl<'tcx> InferCtxt<'tcx> { let ty_sub_vid = self.sub_unification_table_root_var(ty_vid); let inner = &mut *self.inner.borrow_mut(); let mut type_variables = inner.type_variable_storage.with_log(&mut inner.undo_log); - inner.opaque_type_storage.iter_hidden_types_of_opaques().any(|(hidden_ty, _)| { + inner.opaque_type_storage.iter_pseudo_rigids_due_to_opaques().any(|(hidden_ty, _)| { if let ty::Infer(ty::TyVar(hidden_vid)) = *hidden_ty.kind() { let opaque_sub_vid = type_variables.sub_unification_table_root_var(hidden_vid); if opaque_sub_vid == ty_sub_vid { @@ -1191,10 +1194,10 @@ impl<'tcx> InferCtxt<'tcx> { .collect() } - pub fn hidden_types_of_opaques_modulo_sub_unification( + pub fn pseudo_rigids_due_to_opaques_modulo_self_unification( &self, ty_vid: TyVid, - ) -> Vec<(Ty<'tcx>, Vec>)> { + ) -> Vec<(Ty<'tcx>, Vec>)> { // Avoid accidentally allowing more code to compile with the old solver. if !self.next_trait_solver() { return vec![]; @@ -1207,12 +1210,12 @@ impl<'tcx> InferCtxt<'tcx> { let mut type_variables = inner.type_variable_storage.with_log(&mut inner.undo_log); inner .opaque_type_storage - .iter_hidden_types_of_opaques() - .filter_map(|(hidden_ty, bounds)| { - if let ty::Infer(ty::TyVar(hidden_vid)) = *hidden_ty.kind() { + .iter_pseudo_rigids_due_to_opaques() + .filter_map(|(pseudo_rigid, bounds)| { + if let ty::Infer(ty::TyVar(hidden_vid)) = *pseudo_rigid.kind() { let opaque_sub_vid = type_variables.sub_unification_table_root_var(hidden_vid); if opaque_sub_vid == ty_sub_vid { - return Some((hidden_ty, bounds.iter().copied().collect())); + return Some((pseudo_rigid, bounds.iter().copied().collect())); } } diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index faade40e51df0..9ec2f2f6955a5 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -207,12 +207,12 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().opaque_types().register(opaque_type_key, hidden_ty) } - pub fn add_hidden_type_of_opaque_in_storage( + pub fn register_pseudo_rigid_due_to_opaques_in_storage( &self, - hidden_ty: Ty<'tcx>, - bounds: impl IntoIterator>, + pseudo_rigid: Ty<'tcx>, + bounds: impl IntoIterator>, ) { - let ty::Infer(ty::TyVar(vid)) = *hidden_ty.kind() else { + let ty::Infer(ty::TyVar(vid)) = *pseudo_rigid.kind() else { return; }; if self.try_resolve_ty_var(vid).is_ok() { @@ -225,35 +225,35 @@ impl<'tcx> InferCtxt<'tcx> { // borrowing the `opaque_type_storage` here. let mut type_variables = inner.type_variable_storage.with_log(&mut inner.undo_log); - // Since we lookup `hidden_types_of_opaques` modulo sub-roots, + // Since we lookup `pseudo_rigids_due_to_opaques` modulo sub-roots, // it's okay to save them with the preexisting key that - // sub-unified with the given `hidden_ty`. + // sub-unified with the given `pseudo_rigid`. // // And doing so helps avoiding possibly duplicates (modulo sub roots) // which is not so good for caching and goal evaluation progress // heuristics. - let hidden_ty = inner + let pseudo_rigid = inner .opaque_type_storage - .iter_hidden_types_of_opaques() - .map(|(hidden_ty, _)| hidden_ty) - .find(|hidden_ty| { - if let ty::Infer(ty::TyVar(hidden_vid)) = *hidden_ty.kind() { - type_variables.sub_unification_table_root_var(hidden_vid) == ty_sub_vid + .iter_pseudo_rigids_due_to_opaques() + .map(|(pr, _)| pr) + .find(|pr| { + if let ty::Infer(ty::TyVar(ty_vid)) = *pr.kind() { + type_variables.sub_unification_table_root_var(ty_vid) == ty_sub_vid } else { false } }) - .unwrap_or(hidden_ty); + .unwrap_or(pseudo_rigid); - inner.opaque_types().add_hidden_type_of_opaque(hidden_ty, bounds); + inner.opaque_types().add_pseudo_rigid_due_to_opaques(pseudo_rigid, bounds); } - pub fn add_opaque_hidden_ty_bounds_in_storage( + pub fn register_pseudo_rigid_due_to_opaques_in_storage_with_flattened( &self, - bounds: &[(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)], + bounds: &[(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)], ) { for chunk in bounds.chunk_by(|a, b| a.0 == b.0) { - self.add_hidden_type_of_opaque_in_storage( + self.register_pseudo_rigid_due_to_opaques_in_storage( chunk[0].0, chunk.iter().map(|(_, bound)| *bound), ); diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index 02dc3e6a37536..2054669540146 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -14,18 +14,23 @@ use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog}; pub struct OpaqueTypeStorage<'tcx> { opaque_types: FxIndexMap, ProvisionalHiddenType<'tcx>>, duplicate_entries: Vec<(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)>, - // Note: - // OpaqueHiddenTy ::= OpaqueTy - // | Projection - // - // When we normalize a `OpaqueHiddenTy`, we store its self-bounds here, to support non-defining - // usages of sucu hidden types. The key is an expected term for the normalization and the value - // is those self-bounds. - hidden_types_of_opaques: FxIndexMap, FxIndexSet>>, - // The flattened version of the above `hidden_types_of_opaques`. This is a pure duplication - // but we need this to track things linearly, so that we can track the number of those bounds - // in `OpaqueTypeStorageEntries` without a map and can lookup `opaque_hidden_ty_bounds` in O(1). - opaque_hidden_ty_bounds: Vec<(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)>, + /// Note: + /// ```text + /// PseudoRigid ::= OpaqueTy + /// | Projection(::AssocTy), + /// where PseudoRigid: Trait is from PseudoRigid's bound + /// ``` + /// + /// When we normalize a `PseudoRigid`, we store its self-bounds here, to support non-defining + /// usages of sucu hidden types. The key is an expected term for the normalization and the value + /// is those self-bounds. + pseudo_rigids_due_to_opaques: + FxIndexMap, FxIndexSet>>, + /// The flattened version of the above `pseudo_rigids_due_to_opaques`. This is a pure duplication + /// but we need this to track things linearly, so that we can track the number of those bounds + /// in [`OpaqueTypeStorageEntries`] without a map and can lookup `pseudo_rigid_due_to_opaques_bounds` + /// in O(1). + pseudo_rigid_due_to_opaques_bounds: Vec<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)>, } /// The number of entries in the opaque type storage at a given point. @@ -36,17 +41,17 @@ pub struct OpaqueTypeStorage<'tcx> { pub struct OpaqueTypeStorageEntries { opaque_types: usize, duplicate_entries: usize, - opaque_hidden_ty_bounds: usize, + pseudo_rigid_due_to_opaques_bounds: usize, } impl rustc_type_ir::inherent::OpaqueTypeStorageEntries for OpaqueTypeStorageEntries { - fn needs_reevaluation(self, opaques: usize, hidden_ty_bounds: usize) -> bool { + fn needs_reevaluation(self, opaques: usize, pseudo_rigid_bounds: usize) -> bool { let OpaqueTypeStorageEntries { opaque_types, duplicate_entries: _, - opaque_hidden_ty_bounds, + pseudo_rigid_due_to_opaques_bounds, } = self; - opaques != opaque_types || hidden_ty_bounds != opaque_hidden_ty_bounds + opaques != opaque_types || pseudo_rigid_bounds != pseudo_rigid_due_to_opaques_bounds } } @@ -72,62 +77,64 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { assert!(entry.is_some()); } - pub(crate) fn truncate_hidden_types_of_opaques( + pub(crate) fn truncate_pseudo_rigids_due_to_opaques( &mut self, hidden_ty: Ty<'tcx>, len: Option, ) { let removed = if let Some(len) = len { - let bounds = self.hidden_types_of_opaques.get_mut(&hidden_ty).unwrap(); + let bounds = self.pseudo_rigids_due_to_opaques.get_mut(&hidden_ty).unwrap(); let removed = bounds.len() - len; bounds.truncate(len); removed } else { - match self.hidden_types_of_opaques.swap_remove(&hidden_ty) { + match self.pseudo_rigids_due_to_opaques.swap_remove(&hidden_ty) { None => bug!( - "reverted opaque hidden type inference that was never registered: {:?}", + "reverted pseudo-rigid type inference that was never registered: {:?}", hidden_ty ), Some(bounds) => bounds.len(), } }; - let truncate_to = self.opaque_hidden_ty_bounds.len() - removed; + let truncate_to = self.pseudo_rigid_due_to_opaques_bounds.len() - removed; debug_assert!( - (&self.opaque_hidden_ty_bounds[truncate_to..]).iter().all(|(h, _)| *h == hidden_ty) + (&self.pseudo_rigid_due_to_opaques_bounds[truncate_to..]) + .iter() + .all(|(h, _)| *h == hidden_ty) ); - self.opaque_hidden_ty_bounds.truncate(truncate_to); + self.pseudo_rigid_due_to_opaques_bounds.truncate(truncate_to); } pub fn is_empty(&self) -> bool { let OpaqueTypeStorage { opaque_types, duplicate_entries, - hidden_types_of_opaques, - opaque_hidden_ty_bounds, + pseudo_rigids_due_to_opaques, + pseudo_rigid_due_to_opaques_bounds, } = self; opaque_types.is_empty() && duplicate_entries.is_empty() - && hidden_types_of_opaques.is_empty() - && opaque_hidden_ty_bounds.is_empty() + && pseudo_rigids_due_to_opaques.is_empty() + && pseudo_rigid_due_to_opaques_bounds.is_empty() } pub(crate) fn take_opaque_types( &mut self, ) -> ( impl Iterator, ProvisionalHiddenType<'tcx>)>, - impl Iterator, FxIndexSet>)>, + impl Iterator, FxIndexSet>)>, ) { let OpaqueTypeStorage { opaque_types, duplicate_entries, - hidden_types_of_opaques, - opaque_hidden_ty_bounds, + pseudo_rigids_due_to_opaques, + pseudo_rigid_due_to_opaques_bounds, } = self; - let _ = std::mem::take(opaque_hidden_ty_bounds); + let _ = std::mem::take(pseudo_rigid_due_to_opaques_bounds); ( std::mem::take(opaque_types).into_iter().chain(std::mem::take(duplicate_entries)), - std::mem::take(hidden_types_of_opaques).into_iter(), + std::mem::take(pseudo_rigids_due_to_opaques).into_iter(), ) } @@ -135,12 +142,12 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { OpaqueTypeStorageEntries { opaque_types: self.opaque_types.len(), duplicate_entries: self.duplicate_entries.len(), - opaque_hidden_ty_bounds: self.opaque_hidden_ty_bounds.len(), + pseudo_rigid_due_to_opaques_bounds: self.pseudo_rigid_due_to_opaques_bounds.len(), } } - pub fn num_opaque_hidden_ty_bounds(&self) -> usize { - self.opaque_hidden_ty_bounds.len() + pub fn num_pseudo_rigid_due_to_opaques_bounds(&self) -> usize { + self.pseudo_rigid_due_to_opaques_bounds.len() } pub fn opaque_types_added_since( @@ -154,12 +161,16 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { .chain(self.duplicate_entries.iter().skip(prev_entries.duplicate_entries).copied()) } - pub fn opaque_hidden_ty_bounds_added_since( + pub fn pseudo_rigid_due_to_opaques_bounds_added_since( &self, prev_entries: OpaqueTypeStorageEntries, - ) -> impl Iterator, ty::OpaqueHiddenTyBound<'tcx>)> { - self.opaque_hidden_ty_bounds.iter().skip(prev_entries.opaque_hidden_ty_bounds).copied() + ) -> impl Iterator, ty::PseudoRigidDueToOpaquesBound<'tcx>)> { + self.pseudo_rigid_due_to_opaques_bounds + .iter() + .skip(prev_entries.pseudo_rigid_due_to_opaques_bounds) + .copied() } + /// Only returns the opaque types from the lookup table. These are used /// when normalizing opaque types and have a unique key. /// @@ -188,34 +199,34 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { let OpaqueTypeStorage { opaque_types, duplicate_entries, - hidden_types_of_opaques: _, - opaque_hidden_ty_bounds: _, + pseudo_rigids_due_to_opaques: _, + pseudo_rigid_due_to_opaques_bounds: _, } = self; opaque_types.iter().map(|(k, v)| (*k, *v)).chain(duplicate_entries.iter().copied()) } - pub fn iter_hidden_types_of_opaques( + pub fn iter_pseudo_rigids_due_to_opaques( &self, - ) -> impl Iterator, &FxIndexSet>)> { + ) -> impl Iterator, &FxIndexSet>)> { let OpaqueTypeStorage { opaque_types: _, duplicate_entries: _, - hidden_types_of_opaques, - opaque_hidden_ty_bounds: _, + pseudo_rigids_due_to_opaques, + pseudo_rigid_due_to_opaques_bounds: _, } = self; - hidden_types_of_opaques.iter().map(|(hidden, bounds)| (*hidden, bounds)) + pseudo_rigids_due_to_opaques.iter().map(|(pr, bounds)| (*pr, bounds)) } - pub fn iter_opaque_hidden_ty_bounds( + pub fn iter_pseudo_rigid_due_to_opaques_bounds( &self, - ) -> impl Iterator, ty::OpaqueHiddenTyBound<'tcx>)> { + ) -> impl Iterator, ty::PseudoRigidDueToOpaquesBound<'tcx>)> { let OpaqueTypeStorage { opaque_types: _, duplicate_entries: _, - hidden_types_of_opaques: _, - opaque_hidden_ty_bounds, + pseudo_rigids_due_to_opaques: _, + pseudo_rigid_due_to_opaques_bounds, } = self; - opaque_hidden_ty_bounds.iter().copied() + pseudo_rigid_due_to_opaques_bounds.iter().copied() } #[inline] @@ -265,18 +276,18 @@ impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> { self.undo_log.push(UndoLog::DuplicateOpaqueType); } - pub fn add_hidden_type_of_opaque( + pub fn add_pseudo_rigid_due_to_opaques( &mut self, - hidden_ty: Ty<'tcx>, - bounds: impl IntoIterator>, + pseudo_rigid: Ty<'tcx>, + bounds: impl IntoIterator>, ) { let OpaqueTypeStorage { opaque_types: _, duplicate_entries: _, - hidden_types_of_opaques, - opaque_hidden_ty_bounds, + pseudo_rigids_due_to_opaques, + pseudo_rigid_due_to_opaques_bounds, } = self.storage; - let prev_len = match hidden_types_of_opaques.entry(hidden_ty) { + let prev_len = match pseudo_rigids_due_to_opaques.entry(pseudo_rigid) { Entry::Occupied(mut entry) => { let entry = entry.get_mut(); let len = entry.len(); @@ -284,8 +295,8 @@ impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> { if entry.len() == len { return; } - opaque_hidden_ty_bounds - .extend(iter::repeat(hidden_ty).zip(entry.iter().skip(len).copied())); + pseudo_rigid_due_to_opaques_bounds + .extend(iter::repeat(pseudo_rigid).zip(entry.iter().skip(len).copied())); Some(len) } Entry::Vacant(vacant) => { @@ -294,10 +305,11 @@ impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> { return; } let entry = vacant.insert(bounds); - opaque_hidden_ty_bounds.extend(iter::repeat(hidden_ty).zip(entry.iter().copied())); + pseudo_rigid_due_to_opaques_bounds + .extend(iter::repeat(pseudo_rigid).zip(entry.iter().copied())); None } }; - self.undo_log.push(UndoLog::HiddenTypesOfOpaques(hidden_ty, prev_len)); + self.undo_log.push(UndoLog::PseudoRigidDueToOpaques(pseudo_rigid, prev_len)); } } diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs index a4e55945e819e..85b8b81d7347f 100644 --- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs +++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs @@ -20,7 +20,7 @@ pub struct Snapshot<'tcx> { pub(crate) enum UndoLog<'tcx> { DuplicateOpaqueType, OpaqueTypes(OpaqueTypeKey<'tcx>, Option>), - HiddenTypesOfOpaques(Ty<'tcx>, Option), + PseudoRigidDueToOpaques(Ty<'tcx>, Option), TypeVariables(type_variable::UndoLog<'tcx>), ConstUnificationTable(sv::UndoLog>>), IntUnificationTable(sv::UndoLog>), @@ -68,8 +68,8 @@ impl<'tcx> Rollback> for InferCtxtInner<'tcx> { match undo { UndoLog::DuplicateOpaqueType => self.opaque_type_storage.pop_duplicate_entry(), UndoLog::OpaqueTypes(key, idx) => self.opaque_type_storage.remove(key, idx), - UndoLog::HiddenTypesOfOpaques(ty, len) => { - self.opaque_type_storage.truncate_hidden_types_of_opaques(ty, len) + UndoLog::PseudoRigidDueToOpaques(ty, len) => { + self.opaque_type_storage.truncate_pseudo_rigids_due_to_opaques(ty, len) } UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo), UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo), diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 1fa9348821590..61e30042da075 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -70,7 +70,7 @@ pub struct MethodAutoderefSteps<'tcx> { /// /// Only used by the new solver for now. pub predefined_opaques_in_body: solve::PredefinedOpaques<'tcx>, - pub opaque_hidden_ty_bounds_in_body: solve::OpaqueHiddenTyBounds<'tcx>, + pub pseudo_rigid_due_to_opaques_bounds_in_body: solve::PseudoRigidDueToOpaquesBounds<'tcx>, pub self_ty: Ty<'tcx>, } @@ -156,7 +156,7 @@ impl<'tcx> FromIterator> for DropckConstraint<'tcx> { #[derive(Debug, StableHash)] pub struct CandidateStep<'tcx> { pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, - pub self_ty_is_hidden_ty_of_opaque: bool, + pub self_ty_is_pseudo_rigid_opaques: bool, pub autoderefs: usize, /// `true` if the type results from a dereference of a raw pointer. /// when assembling candidates, we include these steps, but not when diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index c00eacf6e330f..637a3719df37f 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -21,7 +21,8 @@ pub type GoalStalledOnOpaques<'tcx> = ir::solve::GoalStalledOnOpaques = ir::solve::SucceededInErased>; pub type PredefinedOpaques<'tcx> = &'tcx ty::List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>; -pub type OpaqueHiddenTyBounds<'tcx> = &'tcx ty::List<(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)>; +pub type PseudoRigidDueToOpaquesBounds<'tcx> = + &'tcx ty::List<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)>; // Interning CanonicalInput drastically reduces max memory usage when compiling a crate that has // trait solver recursion depth overflows with next-solver deduplicating individual inputs. @@ -74,7 +75,9 @@ impl<'tcx> TypeFoldable> for ExternalConstraints<'tcx> { Ok(FallibleTypeFolder::cx(folder).mk_external_constraints(ExternalConstraintsData { region_constraints: self.region_constraints.clone().try_fold_with(folder)?, opaque_types: self.opaque_types.try_fold_with(folder)?, - opaque_hidden_ty_bounds: self.opaque_hidden_ty_bounds.try_fold_with(folder)?, + pseudo_rigid_due_to_opaques_bounds: self + .pseudo_rigid_due_to_opaques_bounds + .try_fold_with(folder)?, normalization_nested_goals: self .normalization_nested_goals .clone() @@ -93,7 +96,9 @@ impl<'tcx> TypeFoldable> for ExternalConstraints<'tcx> { TypeFolder::cx(folder).mk_external_constraints(ExternalConstraintsData { region_constraints: self.region_constraints.clone().fold_with(folder), opaque_types: self.opaque_types.fold_with(folder), - opaque_hidden_ty_bounds: self.opaque_hidden_ty_bounds.fold_with(folder), + pseudo_rigid_due_to_opaques_bounds: self + .pseudo_rigid_due_to_opaques_bounds + .fold_with(folder), normalization_nested_goals: self.normalization_nested_goals.clone().fold_with(folder), }) } @@ -104,13 +109,13 @@ impl<'tcx> TypeVisitable> for ExternalConstraints<'tcx> { let ExternalConstraintsData { region_constraints, opaque_types, - opaque_hidden_ty_bounds, + pseudo_rigid_due_to_opaques_bounds, normalization_nested_goals, } = &**self; try_visit!(region_constraints.visit_with(visitor)); try_visit!(opaque_types.visit_with(visitor)); - try_visit!(opaque_hidden_ty_bounds.visit_with(visitor)); + try_visit!(pseudo_rigid_due_to_opaques_bounds.visit_with(visitor)); normalization_nested_goals.visit_with(visitor) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 411ace170870e..1760d1326b814 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -66,7 +66,7 @@ use crate::thir::Thir; use crate::traits; use crate::traits::solve::{ CanonicalInput, CanonicalInputData, ExternalConstraints, ExternalConstraintsData, - OpaqueHiddenTyBounds, PredefinedOpaques, + PredefinedOpaques, PseudoRigidDueToOpaquesBounds, }; use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; use crate::ty::{ @@ -159,8 +159,8 @@ pub struct CtxtInterners<'tcx> { adt_def: InternedSet<'tcx, AdtDefData>, external_constraints: InternedSet<'tcx, ExternalConstraintsData>>, predefined_opaques_in_body: InternedSet<'tcx, List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>>, - hidden_types_of_opaques_in_body: - InternedSet<'tcx, List<(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)>>, + pseudo_rigid_due_to_opaques_bounds_in_body: + InternedSet<'tcx, List<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)>>, fields: InternedSet<'tcx, List>, local_def_ids: InternedSet<'tcx, List>, captures: InternedSet<'tcx, List<&'tcx ty::CapturedPlace<'tcx>>>, @@ -200,7 +200,7 @@ impl<'tcx> CtxtInterners<'tcx> { adt_def: InternedSet::with_capacity(N), external_constraints: InternedSet::with_capacity(N), predefined_opaques_in_body: InternedSet::with_capacity(N), - hidden_types_of_opaques_in_body: InternedSet::with_capacity(N * 2), + pseudo_rigid_due_to_opaques_bounds_in_body: InternedSet::with_capacity(N * 2), fields: InternedSet::with_capacity(N * 4), local_def_ids: InternedSet::with_capacity(N), captures: InternedSet::with_capacity(N), @@ -2066,7 +2066,7 @@ slice_interners!( patterns: pub mk_patterns(Pattern<'tcx>), outlives: pub mk_outlives(ty::ArgOutlivesClause<'tcx>), predefined_opaques_in_body: pub mk_predefined_opaques_in_body((ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)), - hidden_types_of_opaques_in_body: pub mk_opaque_hidden_ty_bounds_in_body((Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)), + pseudo_rigid_due_to_opaques_bounds_in_body: pub mk_pseudo_rigid_due_to_opaques_bounds_in_body((Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)), ); impl<'tcx> TyCtxt<'tcx> { @@ -2562,12 +2562,15 @@ impl<'tcx> TyCtxt<'tcx> { T::collect_and_apply(iter, |xs| self.mk_predefined_opaques_in_body(xs)) } - pub fn mk_opaque_hidden_ty_bounds_in_body_from_iter(self, iter: I) -> T::Output + pub fn mk_pseudo_rigid_due_to_opaques_bounds_in_body_from_iter(self, iter: I) -> T::Output where I: Iterator, - T: CollectAndApply<(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>), OpaqueHiddenTyBounds<'tcx>>, + T: CollectAndApply< + (Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>), + PseudoRigidDueToOpaquesBounds<'tcx>, + >, { - T::collect_and_apply(iter, |xs| self.mk_opaque_hidden_ty_bounds_in_body(xs)) + T::collect_and_apply(iter, |xs| self.mk_pseudo_rigid_due_to_opaques_bounds_in_body(xs)) } pub fn mk_clauses_from_iter(self, iter: I) -> T::Output diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 880a2c6b59c67..c25f5578f8e1d 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -76,13 +76,13 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.mk_predefined_opaques_in_body(data) } - type OpaqueHiddenTyBounds = solve::OpaqueHiddenTyBounds<'tcx>; + type PseudoRigidDueToOpaquesBounds = solve::PseudoRigidDueToOpaquesBounds<'tcx>; - fn mk_opaque_hidden_ty_bounds_in_body( + fn mk_pseudo_rigid_due_to_opaques_bounds_in_body( self, - data: &[(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)], - ) -> Self::OpaqueHiddenTyBounds { - self.mk_opaque_hidden_ty_bounds_in_body(data) + data: &[(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)], + ) -> Self::PseudoRigidDueToOpaquesBounds { + self.mk_pseudo_rigid_due_to_opaques_bounds_in_body(data) } type LocalDefIds = &'tcx ty::List; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 1b96272e56902..0757059687f7a 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -79,7 +79,7 @@ pub use self::fold::*; pub use self::instance::{Instance, InstanceKind, ReifyReason, ShimKind}; pub(crate) use self::list::RawList; pub use self::list::{List, ListWithCachedTypeInfo}; -pub use self::opaque_types::{OpaqueHiddenTyBound, OpaqueTypeKey}; +pub use self::opaque_types::{OpaqueTypeKey, PseudoRigidDueToOpaquesBound}; pub use self::pattern::{Pattern, PatternKind}; pub use self::predicate::{ AliasTerm, AliasTermKind, ArgOutlivesClause, Clause, ClauseKind, CoercePredicate, diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index 293e7268c3f89..1f1b489020bfb 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -10,7 +10,8 @@ use crate::ty::{ pub type OpaqueTypeKey<'tcx> = rustc_type_ir::OpaqueTypeKey>; -pub type OpaqueHiddenTyBound<'tcx> = rustc_type_ir::OpaqueHiddenTyBound>; +pub type PseudoRigidDueToOpaquesBound<'tcx> = + rustc_type_ir::PseudoRigidDueToOpaquesBound>; /// Converts generic params of a TypeFoldable from one /// item's generics to another. Usually from a function's generics diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 2549b11acabf5..1279ddcbbdf02 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -760,7 +760,7 @@ macro_rules! list_fold { list_fold! { &'tcx ty::List> : mk_poly_existential_predicates, &'tcx ty::List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>: mk_predefined_opaques_in_body, - &'tcx ty::List<(Ty<'tcx>, ty::OpaqueHiddenTyBound<'tcx>)>: mk_opaque_hidden_ty_bounds_in_body, + &'tcx ty::List<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)>: mk_pseudo_rigid_due_to_opaques_bounds_in_body, &'tcx ty::List> : mk_place_elems, &'tcx ty::List> : mk_patterns, &'tcx ty::List> : mk_outlives, diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 8e85b5cc43537..69d8d425434a9 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -116,7 +116,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { let RawExternalConstraintsData { region_constraints, opaque_types, - opaque_hidden_ty_bounds: mut opaque_hidden_ty_bounds_candidates, + pseudo_rigid_due_to_opaques_bounds, normalization_nested_goals, } = external_constraints; let region_constraints = if region_constraints.has_type_flags(NEEDS_CANONICAL) { @@ -135,28 +135,10 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { } else { normalization_nested_goals }; - - // Filter out irrelevant hidden tys, in a fixed-point iteration to make them less bulky. - let mut opaque_hidden_ty_bounds = vec![]; - while !opaque_hidden_ty_bounds_candidates.is_empty() { - let prev_len = opaque_hidden_ty_bounds.len(); - opaque_hidden_ty_bounds_candidates.retain(|bounds @ (hidden_ty, _)| { - if let ty::Infer(ty::TyVar(vid)) = hidden_ty.kind() - && canonicalizer - .state - .sub_root_lookup_table - .contains_key(&delegate.sub_unification_table_root_var(vid)) - { - opaque_hidden_ty_bounds.push(bounds.clone().fold_with(&mut canonicalizer)); - false - } else { - true - } - }); - if opaque_hidden_ty_bounds.len() == prev_len { - break; - } - } + let pseudo_rigid_due_to_opaques_bounds = canonicalizer + .filter_and_canonicalize_pseudo_rigids_due_to_opaques_bounds( + pseudo_rigid_due_to_opaques_bounds, + ); let value = Response { certainty, @@ -164,9 +146,11 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { external_constraints: delegate.cx().mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types: delegate.cx().mk_predefined_opaques_in_body(&opaque_types), - opaque_hidden_ty_bounds: delegate + pseudo_rigid_due_to_opaques_bounds: delegate .cx() - .mk_opaque_hidden_ty_bounds_in_body(&opaque_hidden_ty_bounds), + .mk_pseudo_rigid_due_to_opaques_bounds_in_body( + &pseudo_rigid_due_to_opaques_bounds, + ), normalization_nested_goals, }), }; @@ -302,36 +286,21 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { predefined_opaques_in_body }; - // Filter out irrelevant hidden tys, in a fixed-point iteration. Otherwise it would make - // the query heavy and less cache-friendly. - let mut hidden_types_of_opaques_in_body_candidates = - input.hidden_types_of_opaques_in_body.to_vec(); - let mut hidden_types_of_opaques_in_body = vec![]; - while !hidden_types_of_opaques_in_body_candidates.is_empty() { - let prev_len = hidden_types_of_opaques_in_body.len(); - hidden_types_of_opaques_in_body_candidates.retain(|bound @ (hidden_ty, _)| { - if let ty::Infer(ty::TyVar(vid)) = hidden_ty.kind() - && rest_canonicalizer - .state - .sub_root_lookup_table - .contains_key(&delegate.sub_unification_table_root_var(vid)) - { - hidden_types_of_opaques_in_body.push(bound.fold_with(&mut rest_canonicalizer)); - false - } else { - true - } - }); - if hidden_types_of_opaques_in_body.len() == prev_len { - break; - } - } + let pseudo_rigid_due_to_opaques_bounds_in_body = rest_canonicalizer + .filter_and_canonicalize_pseudo_rigids_due_to_opaques_bounds( + input.pseudo_rigid_due_to_opaques_bounds_in_body.to_vec(), + ); - let hidden_types_of_opaques_in_body = - delegate.cx().mk_opaque_hidden_ty_bounds_in_body(&hidden_types_of_opaques_in_body); + let pseudo_rigid_due_to_opaques_bounds_in_body = + delegate.cx().mk_pseudo_rigid_due_to_opaques_bounds_in_body( + &pseudo_rigid_due_to_opaques_bounds_in_body, + ); - let value = - QueryInput { goal, predefined_opaques_in_body, hidden_types_of_opaques_in_body }; + let value = QueryInput { + goal, + predefined_opaques_in_body, + pseudo_rigid_due_to_opaques_bounds_in_body, + }; debug_assert!(!value.has_infer(), "unexpected infer in {value:?}"); debug_assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); @@ -521,6 +490,44 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { Ty::new_canonical_bound(self.cx(), var) } + + /// After canonicalizing all the other relevant values, filter out pseudo-rigids that + /// sub-unified with no other existing vars and canonicalize the remaining ones. + fn filter_and_canonicalize_pseudo_rigids_due_to_opaques_bounds( + &mut self, + mut pseudo_rigid_due_to_opaques_bounds: Vec<(I::Ty, ty::PseudoRigidDueToOpaquesBound)>, + ) -> Vec<(I::Ty, ty::PseudoRigidDueToOpaquesBound)> { + let mut filtered = vec![]; + + // This should be done in fixed-point iteration, because we may have some pseudo-rigid + // that sub-unified with an infer var in another one's bounds. + // Fox example, suppose that we have `[?x]` for `var_values` and + // `[(?y, ^self: Foo), (?x, ^self: Bar)]` for pseudo-rigids. If we check them just + // once in order, we accidentally filter out the first `(?y, ^self: foo)` as `?y` + // appears nowhere in preexisting `var_values` when we check it, but it becomes relevant + // after we check and canonicalize the second one. + while !pseudo_rigid_due_to_opaques_bounds.is_empty() { + let prev_len = filtered.len(); + pseudo_rigid_due_to_opaques_bounds.retain(|bounds @ (hidden_ty, _)| { + if let ty::Infer(ty::TyVar(vid)) = hidden_ty.kind() + && self + .state + .sub_root_lookup_table + .contains_key(&self.delegate.sub_unification_table_root_var(vid)) + { + filtered.push(bounds.clone().fold_with(self)); + false + } else { + true + } + }); + if filtered.len() == prev_len { + break; + } + } + + filtered + } } impl, I: Interner> TypeFolder for Canonicalizer<'_, D, I> { diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index 03342e238912b..280f1ed3ccc35 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -57,7 +57,7 @@ pub(super) fn canonicalize_goal( delegate: &D, goal: Goal, opaque_types: &[(ty::OpaqueTypeKey, I::Ty)], - opaque_hidden_ty_bounds: &[(I::Ty, ty::OpaqueHiddenTyBound)], + pseudo_rigid_due_to_opaques_bounds: &[(I::Ty, ty::PseudoRigidDueToOpaquesBound)], typing_mode: TypingMode, ) -> (ThinVec, I::CanonicalInput) where @@ -69,9 +69,9 @@ where QueryInput { goal, predefined_opaques_in_body: delegate.cx().mk_predefined_opaques_in_body(opaque_types), - hidden_types_of_opaques_in_body: delegate + pseudo_rigid_due_to_opaques_bounds_in_body: delegate .cx() - .mk_opaque_hidden_ty_bounds_in_body(opaque_hidden_ty_bounds), + .mk_pseudo_rigid_due_to_opaques_bounds_in_body(pseudo_rigid_due_to_opaques_bounds), }, ); @@ -131,7 +131,7 @@ where let ExternalConstraintsData { region_constraints, opaque_types, - opaque_hidden_ty_bounds, + pseudo_rigid_due_to_opaques_bounds, normalization_nested_goals, } = &*external_constraints; @@ -154,7 +154,9 @@ where } }; register_new_opaque_types(delegate, opaque_types.as_slice(), span); - delegate.add_opaque_hidden_ty_bounds_in_storage(opaque_hidden_ty_bounds.as_slice()); + delegate.register_pseudo_rigid_due_to_opaques_in_storage_with_flattened( + pseudo_rigid_due_to_opaques_bounds.as_slice(), + ); (normalization_nested_goals.clone(), certainty) } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 1ef3ec6af2a45..eb993d0eb5914 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -57,6 +57,8 @@ where fn trait_def_id(self, cx: I) -> I::TraitId; + fn as_normalizes_to(self) -> Option>; + /// Consider a clause, which consists of a "assumption" and some "requirements", /// to satisfy a goal. If the requirements hold, then attempt to satisfy our /// goal by equating it with the assumption. @@ -431,25 +433,6 @@ where ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolutionOrRerunNonErased>; - - fn consider_hidden_types_of_opaques_bound_candidate( - ecx: &mut EvalCtxt<'_, D>, - goal: Goal, - bound: ty::OpaqueHiddenTyBound, - ) -> Result, NoSolutionOrRerunNonErased> { - let assumption = bound.instantiate(ecx.cx(), goal.predicate.self_ty()); - Self::probe_and_match_goal_against_assumption( - ecx, - CandidateSource::AliasBound(AliasBoundKind::SelfBounds), - goal, - assumption, - |ecx| { - // We want to reprove this goal once we've inferred the - // hidden type, so we force the certainty to `Maybe`. - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - }, - ) - } } /// Allows callers of `assemble_and_evaluate_candidates` to choose whether to limit @@ -1146,11 +1129,61 @@ where assemble_from: AssembleCandidatesFrom, candidates: &mut Vec>, ) -> Result<(), RerunNonErased> { + fn consider_pseudo_rigid_due_to_opaques_bound( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + bound: ty::PseudoRigidDueToOpaquesBound, + ) -> Result, NoSolutionOrRerunNonErased> + where + D: SolverDelegate, + I: Interner, + G: GoalKind, + { + let cx = ecx.cx(); + let assumption = bound.instantiate(cx, goal.predicate.self_ty()); + G::probe_and_match_goal_against_assumption( + ecx, + CandidateSource::AliasBound(AliasBoundKind::SelfBounds), + goal, + assumption, + |ecx| { + let cx = ecx.cx(); + // If we are normalzing a projection onto a pseudo-rigid, register it as a new + // pseudo-rigid with its bounds. + // This new pseudo-rigid should be added to storage in this scope, when we actually + // use the bound as a candidate, otherwise it may prevent us from considering blanket impl + // candidate when we should. + // See `tests/ui/impl-trait/non-defining-uses/use-blanket-impl.rs` as an example of such case. + if let Some(ty::NormalizesTo { alias, term }) = + G::as_normalizes_to(goal.predicate) + && let ty::AliasTermKind::ProjectionTy { def_id } = alias.kind + && ecx.typing_mode().should_register_pseudo_rigids_due_to_opaques() + { + ecx.add_hidden_type_of_opaque_in_storage( + term.expect_ty(), + ty::PseudoRigidDueToOpaquesBound::iter_item_self_bounds_for_hidden_ty( + cx, + ty::AliasTy::new_from_args( + cx, + ty::AliasTyKind::Projection { def_id }, + alias.args, + ), + ), + ); + } + + // We want to reprove this goal once we've inferred the + // hidden type, so we force the certainty to `Maybe`. + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + }, + ) + } + let self_ty = goal.predicate.self_ty(); // We only use this hack during HIR typeck. - let hidden_types_of_opaques = match self.typing_mode() { + let hidden_tys_of_opaques = match self.typing_mode() { TypingMode::Typeck { .. } => { - self.hidden_types_of_opaques_modulo_sub_unification(self_ty) + self.pseudo_rigids_due_to_opaques_modulo_sub_unification(self_ty) } TypingMode::Coherence | TypingMode::PostTypeckUntilBorrowck { .. } @@ -1165,15 +1198,15 @@ where } }; - if hidden_types_of_opaques.is_empty() { + if hidden_tys_of_opaques.is_empty() { candidates.extend(self.forced_ambiguity(MaybeInfo::AMBIGUOUS)); return Ok(()); } - for (hidden_ty, bounds) in hidden_types_of_opaques { + for (hidden_ty, bounds) in &hidden_tys_of_opaques { debug!("self ty is sub unified with {hidden_ty:?}"); - // We look at all item-bounds of the hidden types, replacing the + // We look at all item-bounds of the type being pseudo rigid due to opaques, // instantiating the self type of the bound with the current self // type before considering them as a candidate. Imagine we've got // `?x: Trait` and `?x` has been sub-unified with the hidden @@ -1181,11 +1214,29 @@ where // and replace all occurrences of `opaque` with `?x`. This results // in a `?x: Trait` alias-bound candidate. for bound in bounds { - candidates - .extend(G::consider_hidden_types_of_opaques_bound_candidate(self, goal, bound)); + candidates.extend(consider_pseudo_rigid_due_to_opaques_bound(self, goal, *bound)); } } + // This is rather hacky and unprincipled, but we nee this anyway :( + // See the comments on + // `[ty::PseudoRigidDueToOpaquesBound::opt_unmentioned_projection_bound]` + // for details. + if self.typing_mode().should_register_pseudo_rigids_due_to_opaques() + && candidates.is_empty() + && let Some(ty::NormalizesTo { alias, term }) = G::as_normalizes_to(goal.predicate) + && term.as_type().is_some() + && let Some(unmentioned) = + ty::PseudoRigidDueToOpaquesBound::opt_unmentioned_projection_bound( + self.cx(), + hidden_tys_of_opaques.into_iter().flat_map(|(_, bounds)| bounds), + ty::ProjectionClause { projection_term: alias, term }, + ) + { + self.add_hidden_type_of_opaque_in_storage(goal.predicate.self_ty(), [unmentioned]); + candidates.extend(consider_pseudo_rigid_due_to_opaques_bound(self, goal, unmentioned)); + } + // If the self type is sub unified with any opaque type, we also look at blanket // impls for it. // diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 04d1376d20b9f..ba4188422ede5 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -39,6 +39,10 @@ where self.def_id() } + fn as_normalizes_to(self) -> Option> { + None + } + fn fast_reject_assumption( ecx: &mut EvalCtxt<'_, D>, goal: Goal, diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index eea65a982583e..f274ceb5ea4be 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -24,7 +24,9 @@ use rustc_type_ir::{ use thin_vec::ThinVec; use tracing::{Level, debug, instrument, trace, warn}; -use super::{RawExternalConstraintsData, has_only_region_constraints_or_opaque_hidden_ty_bounds}; +use super::{ + RawExternalConstraintsData, has_only_region_constraints_or_pseudo_rigid_due_to_opaques_bounds, +}; use crate::canonical::{ canonicalize_goal, canonicalize_response, instantiate_and_apply_query_response, response_no_constraints_raw, @@ -544,8 +546,8 @@ where } } - delegate.add_opaque_hidden_ty_bounds_in_storage( - input.hidden_types_of_opaques_in_body.as_slice(), + delegate.register_pseudo_rigid_due_to_opaques_in_storage_with_flattened( + input.pseudo_rigid_due_to_opaques_bounds_in_body.as_slice(), ); let initial_opaque_types_storage_num_entries = delegate.opaque_types_storage_num_entries(); @@ -770,21 +772,26 @@ where // so we only canonicalize the lookup table and ignore // duplicate entries. let opaque_types = self.delegate.clone_opaque_types_lookup_table(); - let hidden_types_of_opaques = self.delegate.clone_opaque_hidden_ty_bounds(); + let pseudo_rigid_due_to_opaques_bounds = + self.delegate.clone_pseudo_rigid_due_to_opaques_bounds(); - let (goal, opaque_types, opaque_hidden_ty_bounds) = self - .delegate - .deeply_resolve_via_unification_table((goal, opaque_types, hidden_types_of_opaques)); + let (goal, opaque_types, pseudo_rigid_due_to_opaques_bounds) = + self.delegate.deeply_resolve_via_unification_table(( + goal, + opaque_types, + pseudo_rigid_due_to_opaques_bounds, + )); let typing_mode = self.typing_mode(); let step_kind = self.step_kind_for_source(source); let tracing_span = tracing::span!( Level::DEBUG, "evaluate_goal_raw in typing mode", - "{:?} opaques={:?}, opaque_hidden_ty_bounds={:?}", + "{:?} opaques={:?}, pseudo_rigid_due_to_opques_bounds={:?}, goal={:?}", typing_mode, opaque_types, - opaque_hidden_ty_bounds, + pseudo_rigid_due_to_opaques_bounds, + goal, ) .entered(); @@ -872,7 +879,7 @@ where self.delegate, goal, &opaque_types, - &opaque_hidden_ty_bounds, + &pseudo_rigid_due_to_opaques_bounds, typing_mode, ); @@ -900,7 +907,7 @@ where drop(tracing_span); - let before_instantiate_response = self.delegate.num_opaque_hidden_ty_bounds(); + let before_instantiate_response = self.delegate.num_pseudo_rigid_due_to_opaques_bounds(); let (normalization_nested_goals, certainty) = instantiate_and_apply_query_response( self.delegate, @@ -909,18 +916,20 @@ where self.origin_span, ); - // `opaque_hidden_ty_bounds` may vary modulo regions which might be able to be unified in + // `pseudo_rigid_due_to_opaques_bounds` may vary modulo regions which might be able to be unified in // the caller in the end. So, instead of the response has any, check whether the storage // entries actually changed. // // See `tests/ui/traits/next-solver/opaques/non-defining-use-stall-on-no-actual-change-in-the-caller.rs` - let has_changed = if !has_only_region_constraints_or_opaque_hidden_ty_bounds(response) - || self.delegate.num_opaque_hidden_ty_bounds() != before_instantiate_response - { - HasChanged::Yes - } else { - HasChanged::No - }; + let has_changed = + if !has_only_region_constraints_or_pseudo_rigid_due_to_opaques_bounds(response) + || self.delegate.num_pseudo_rigid_due_to_opaques_bounds() + != before_instantiate_response + { + HasChanged::Yes + } else { + HasChanged::No + }; // FIXME: We previously had an assert here that checked that recomputing // a goal after applying its constraints did not change its response. @@ -992,7 +1001,7 @@ where let num_opaques_in_storage = canonical_goal.canonical.value.predefined_opaques_in_body.len(); let num_hidden_ty_bounds_in_storage = - canonical_goal.canonical.value.hidden_types_of_opaques_in_body.len(); + canonical_goal.canonical.value.pseudo_rigid_due_to_opaques_bounds_in_body.len(); GoalStalledOn { stalled_vars, @@ -1517,15 +1526,9 @@ where pub(super) fn add_hidden_type_of_opaque_in_storage( &self, hidden_ty: I::Ty, - bounds: impl IntoIterator>, - ) { - self.delegate.add_hidden_type_of_opaque_in_storage(hidden_ty, bounds); - } - pub(super) fn add_opaque_hidden_ty_bounds_in_storage( - &self, - bounds: &[(I::Ty, ty::OpaqueHiddenTyBound)], + bounds: impl IntoIterator>, ) { - self.delegate.add_opaque_hidden_ty_bounds_in_storage(bounds); + self.delegate.register_pseudo_rigid_due_to_opaques_in_storage(hidden_ty, bounds); } pub(super) fn add_item_bounds_for_hidden_type( @@ -1640,12 +1643,12 @@ where Ok(may_use_unstable_feature(&**self.delegate, param_env, symbol)) } - pub(crate) fn hidden_types_of_opaques_modulo_sub_unification( + pub(crate) fn pseudo_rigids_due_to_opaques_modulo_sub_unification( &self, self_ty: I::Ty, - ) -> Vec<(I::Ty, Vec>)> { + ) -> Vec<(I::Ty, Vec>)> { if let ty::Infer(ty::TyVar(vid)) = self_ty.kind() { - self.delegate.hidden_types_of_opaques_modulo_sub_unification(vid) + self.delegate.pseudo_rigids_due_to_opaques_modulo_sub_unification(vid) } else { vec![] } @@ -1761,7 +1764,7 @@ where filter_irrelevant_region_constraints(self.delegate, &var_values, &mut external_constraints); - external_constraints.opaque_hidden_ty_bounds.retain(|(hidden_ty, _)| hidden_ty.is_ty_var()); + external_constraints.pseudo_rigid_due_to_opaques_bounds.retain(|(pr, _)| pr.is_ty_var()); let canonical = canonicalize_response( self.delegate, @@ -1832,17 +1835,17 @@ where // to the `var_values`. let initial_entries = self.initial_opaque_types_storage_num_entries; let opaque_types = self.delegate.clone_opaque_types_added_since(initial_entries); - let opaque_hidden_ty_bounds = - self.delegate.clone_opaque_hidden_ty_bounds_added_since(initial_entries); + let pseudo_rigid_due_to_opaques_bounds = + self.delegate.clone_pseudo_rigid_due_to_opaques_bounds_added_since(initial_entries); if self.typing_mode().is_erased_not_coherence() { - assert!(opaque_types.is_empty() && opaque_hidden_ty_bounds.is_empty()); + assert!(opaque_types.is_empty() && pseudo_rigid_due_to_opaques_bounds.is_empty()); } RawExternalConstraintsData { region_constraints, opaque_types, - opaque_hidden_ty_bounds, + pseudo_rigid_due_to_opaques_bounds, normalization_nested_goals, } } @@ -1924,7 +1927,7 @@ fn filter_irrelevant_region_constraints( let RawExternalConstraintsData { region_constraints, opaque_types, - opaque_hidden_ty_bounds, + pseudo_rigid_due_to_opaques_bounds, normalization_nested_goals, } = external_constraints; @@ -1941,7 +1944,7 @@ fn filter_irrelevant_region_constraints( // because we skip the RHS of outlives constraints, and `TypeVisitor` doesn't // have a method we can easily override in order to do this. opaque_types.visit_with(&mut vis); - opaque_hidden_ty_bounds.visit_with(&mut vis); + pseudo_rigid_due_to_opaques_bounds.visit_with(&mut vis); normalization_nested_goals.visit_with(&mut vis); for (constraint, _) in r.iter() { match constraint { @@ -2097,16 +2100,20 @@ pub(super) fn evaluate_root_goal_for_proof_tree, root_depth: usize, ) -> (Result, NoSolution>, inspect::GoalEvaluation) { let opaque_types = delegate.clone_opaque_types_lookup_table(); - let opaque_hidden_ty_bounds = delegate.clone_opaque_hidden_ty_bounds(); - let (goal, opaque_types, opaque_hidden_ty_bounds) = delegate - .deeply_resolve_via_unification_table((goal, opaque_types, opaque_hidden_ty_bounds)); + let pseudo_rigid_due_to_opaques_bounds = delegate.clone_pseudo_rigid_due_to_opaques_bounds(); + let (goal, opaque_types, pseudo_rigid_due_to_opaques_bounds) = delegate + .deeply_resolve_via_unification_table(( + goal, + opaque_types, + pseudo_rigid_due_to_opaques_bounds, + )); let typing_mode = delegate.typing_mode_raw().assert_not_erased(); let (orig_values, canonical_goal) = canonicalize_goal( delegate, goal, &opaque_types, - &opaque_hidden_ty_bounds, + &pseudo_rigid_due_to_opaques_bounds, typing_mode.into(), ); diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 4272da179b712..0814bdcc59926 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -61,13 +61,13 @@ fn has_no_inference_or_external_constraints( let ExternalConstraintsData { ref region_constraints, ref opaque_types, - ref opaque_hidden_ty_bounds, + ref pseudo_rigid_due_to_opaques_bounds, ref normalization_nested_goals, } = *response.value.external_constraints; response.value.var_values.is_identity() && region_constraints.is_empty() && opaque_types.is_empty() - && opaque_hidden_ty_bounds.is_empty() + && pseudo_rigid_due_to_opaques_bounds.is_empty() && normalization_nested_goals.is_empty() } @@ -75,22 +75,22 @@ fn has_only_region_constraints(response: ty::Canonical( +fn has_only_region_constraints_or_pseudo_rigid_due_to_opaques_bounds( response: ty::Canonical>, ) -> bool { let ExternalConstraintsData { region_constraints: _, ref opaque_types, - opaque_hidden_ty_bounds: _, + pseudo_rigid_due_to_opaques_bounds: _, ref normalization_nested_goals, } = *response.value.external_constraints; response.value.var_values.is_identity_modulo_regions() @@ -465,6 +465,6 @@ pub struct GoalEvaluation { pub struct RawExternalConstraintsData { pub region_constraints: ExternalRegionConstraints, pub opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, - pub opaque_hidden_ty_bounds: Vec<(I::Ty, ty::OpaqueHiddenTyBound)>, + pub pseudo_rigid_due_to_opaques_bounds: Vec<(I::Ty, ty::PseudoRigidDueToOpaquesBound)>, pub normalization_nested_goals: NestedNormalizationGoals, } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs index 5408ce00c6930..9c79fd1dcce2d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs @@ -4,8 +4,8 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverProjectionLangItem, SolverTraitLangItem}; use rustc_type_ir::solve::{ - AliasBoundKind, FetchEligibleAssocItemResponse, NoSolutionOrRerunNonErased, - QueryResultOrRerunNonErased, RerunNonErased, RerunReason, RerunResultExt, + FetchEligibleAssocItemResponse, NoSolutionOrRerunNonErased, QueryResultOrRerunNonErased, + RerunNonErased, RerunReason, RerunResultExt, }; use rustc_type_ir::{ self as ty, Const, FieldInfo, Interner, NormalizesTo, PredicateKind, Region, Unnormalized, @@ -180,6 +180,10 @@ where self.trait_def_id(cx) } + fn as_normalizes_to(self) -> Option> { + Some(self) + } + fn fast_reject_assumption( ecx: &mut EvalCtxt<'_, D>, goal: Goal, @@ -1087,48 +1091,6 @@ where ) -> Result, NoSolutionOrRerunNonErased> { unreachable!("try_as_dyn helper trait doesn't have assoc types") } - - fn consider_hidden_types_of_opaques_bound_candidate( - ecx: &mut EvalCtxt<'_, D>, - goal: Goal, - bound: ty::OpaqueHiddenTyBound, - ) -> Result, NoSolutionOrRerunNonErased> { - let NormalizesTo { alias, term } = goal.predicate; - let cx = ecx.cx(); - let assumption = bound.instantiate(cx, alias.self_ty()); - Self::probe_and_match_goal_against_assumption( - ecx, - CandidateSource::AliasBound(AliasBoundKind::SelfBounds), - goal, - assumption, - |ecx| { - // Add self bounds for `::Assoc`. Those bounds should be added to - // storage if and only if `` is proven by - // `ty::OpaqueHiddenTyBound` of an opaque (or another assoc ty on it), otherwise - // it might make blaket impl candidate inapplicable. - // See `tests/ui/impl-trait/non-defining-uses/use-blanket-impl.rs` for such case. - if ecx.typing_mode().should_add_hidden_types_of_opaques() - && let ty::AliasTermKind::ProjectionTy { def_id } = alias.kind - { - ecx.add_hidden_type_of_opaque_in_storage( - term.expect_ty(), - ty::OpaqueHiddenTyBound::iter_item_self_bounds_for_hidden_ty( - cx, - ty::AliasTy::new_from_args( - cx, - ty::AliasTyKind::Projection { def_id }, - alias.args, - ), - ), - ); - } - - // We want to reprove this goal once we've inferred the - // hidden type, so we force the certainty to `Maybe`. - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - }, - ) - } } impl EvalCtxt<'_, D> diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs index 3ec626946e8c3..9d6b8875071ba 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs @@ -3,7 +3,6 @@ mod free_alias; mod inherent; mod opaque_types; -use rustc_type_ir::inherent::*; use rustc_type_ir::solve::QueryResultOrRerunNonErased; use rustc_type_ir::{self as ty, Interner, ProjectionClause}; use tracing::{instrument, trace}; @@ -51,27 +50,6 @@ where let normalizes_to = goal.with(self.cx(), ty::NormalizesTo { alias, term: unconstrained_term }); - // For the reason why we need this hack, see the comments on - // [`ty::OpaqueHiddenTyBound::opt_unmentioned_projection_bound`]. - // We register this hacky bound as lazy as possible, at here instead of at the normalization - // of the initial hidden type. That's because we might acquire the originally unmentioned - // bound while proving other goals and if so we might fail the evaluation due to having - // multiple candidates due to this hacky bound. - if self.typing_mode().should_add_hidden_types_of_opaques() - && unconstrained_term.as_type().is_some() - && alias.self_ty().is_ty_var() - { - let hidden_bounds = - self.hidden_types_of_opaques_modulo_sub_unification(alias.self_ty()); - if let Some(unmentioned) = ty::OpaqueHiddenTyBound::opt_unmentioned_projection_bound( - self.cx(), - hidden_bounds.iter().flat_map(|(_, bounds)| bounds).copied(), - goal.predicate, - ) { - self.add_opaque_hidden_ty_bounds_in_storage(&[(alias.self_ty(), unmentioned)]); - } - } - // We don't want candidate selection when normalizing associated terms to be impacted by // the expected term. Normalization should behave like a function of just the alias being // normalized. Because of this, we use an internal `NormalizesTo` goal for which the diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs index 68653e9bb83bd..f011bd865293c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs @@ -109,18 +109,10 @@ where | TypingMode::Reflection | TypingMode::Codegen => unreachable!(), } - } - self.add_item_bounds_for_hidden_type( - def_id.into(), - normalized_args, - goal.param_env, - expected, - )?; - if self.typing_mode().should_add_hidden_types_of_opaques() { self.add_hidden_type_of_opaque_in_storage( expected, - ty::OpaqueHiddenTyBound::iter_item_self_bounds_for_hidden_ty( + ty::PseudoRigidDueToOpaquesBound::iter_item_self_bounds_for_hidden_ty( cx, ty::AliasTy::new_from_args( cx, @@ -130,6 +122,13 @@ where ), ); } + + self.add_item_bounds_for_hidden_type( + def_id.into(), + normalized_args, + goal.param_env, + expected, + )?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) .map_err(Into::into) } diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index b50127af7311b..e1e87a3ffc1a3 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -49,6 +49,10 @@ where self.def_id() } + fn as_normalizes_to(self) -> Option> { + None + } + fn consider_additional_alias_assumptions( _ecx: &mut EvalCtxt<'_, D>, _goal: Goal, @@ -1314,7 +1318,7 @@ where let ExternalConstraintsData { region_constraints: _, ref opaque_types, - ref opaque_hidden_ty_bounds, + ref pseudo_rigid_due_to_opaques_bounds, ref normalization_nested_goals, } = *candidate.result.value.external_constraints; debug_assert!(normalization_nested_goals.is_empty()); @@ -1323,7 +1327,7 @@ where // inference state. This is safe after typeck, where hidden types are already // fixed and only regions are inferred, but not during typeck while hidden // types may still contain inference variables. - if !opaque_types.is_empty() || !opaque_hidden_ty_bounds.is_empty() { + if !opaque_types.is_empty() || !pseudo_rigid_due_to_opaques_bounds.is_empty() { let typing_mode = self.typing_mode(); match typing_mode { diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 64473f1856437..e0f380c4a3e60 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -277,10 +277,10 @@ impl TypingMode { } /// This is `true` for `Typeck` and `false` otherwise as we take into account the - /// item self bounds for `hidden_types_of_opaques` for that `TypingMode` only. + /// item self bounds for pseudo-rigids for that `TypingMode` only. /// /// See also the documentation on [`TypingMode`] about exhaustive matching. - pub fn should_add_hidden_types_of_opaques(&self) -> bool { + pub fn should_register_pseudo_rigids_due_to_opaques(&self) -> bool { match self { TypingMode::Typeck { .. } => true, TypingMode::PostTypeckUntilBorrowck { .. } @@ -563,25 +563,28 @@ pub trait InferCtxtLike: Sized { type OpaqueTypeStorageEntries: OpaqueTypeStorageEntries; fn opaque_types_storage_num_entries(&self) -> Self::OpaqueTypeStorageEntries; - fn num_opaque_hidden_ty_bounds(&self) -> usize; + fn num_pseudo_rigid_due_to_opaques_bounds(&self) -> usize; fn clone_opaque_types_lookup_table( &self, ) -> Vec<(ty::OpaqueTypeKey, ::Ty)>; - fn clone_opaque_hidden_ty_bounds( + fn clone_pseudo_rigid_due_to_opaques_bounds( &self, - ) -> Vec<(::Ty, ty::OpaqueHiddenTyBound)>; + ) -> Vec<(::Ty, ty::PseudoRigidDueToOpaquesBound)>; fn clone_opaque_types_added_since( &self, prev_entries: Self::OpaqueTypeStorageEntries, ) -> Vec<(ty::OpaqueTypeKey, ::Ty)>; - fn clone_opaque_hidden_ty_bounds_added_since( + fn clone_pseudo_rigid_due_to_opaques_bounds_added_since( &self, prev_entries: Self::OpaqueTypeStorageEntries, - ) -> Vec<(::Ty, ty::OpaqueHiddenTyBound)>; - fn hidden_types_of_opaques_modulo_sub_unification( + ) -> Vec<(::Ty, ty::PseudoRigidDueToOpaquesBound)>; + fn pseudo_rigids_due_to_opaques_modulo_sub_unification( &self, ty_vid: TyVid, - ) -> Vec<(::Ty, Vec>)>; + ) -> Vec<( + ::Ty, + Vec>, + )>; fn register_hidden_type_in_storage( &self, @@ -595,14 +598,17 @@ pub trait InferCtxtLike: Sized { hidden_ty: ::Ty, span: ::Span, ); - fn add_hidden_type_of_opaque_in_storage( + fn register_pseudo_rigid_due_to_opaques_in_storage( &self, hidden_ty: ::Ty, - bounds: impl IntoIterator>, + bounds: impl IntoIterator>, ); - fn add_opaque_hidden_ty_bounds_in_storage( + fn register_pseudo_rigid_due_to_opaques_in_storage_with_flattened( &self, - bounds: &[(::Ty, ty::OpaqueHiddenTyBound)], + bounds: &[( + ::Ty, + ty::PseudoRigidDueToOpaquesBound, + )], ); fn reset_opaque_types(&self); diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index d66036b90c383..d6bd21efb56ba 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -643,8 +643,8 @@ pub trait Span: Copy + Debug + Hash + Eq + TypeFoldable { pub trait OpaqueTypeStorageEntries: Debug + Clone + Copy + Default + PartialEq + Eq { /// Whether the number of opaques has changed in a way that necessitates /// reevaluating a goal. For now, this is only when the number of non-duplicated - /// entries and bounds for hidden types of opaques changed. - fn needs_reevaluation(self, opaques: usize, hidden_ty_bounds: usize) -> bool; + /// entries and bounds for pseudo-rigids due to opaques changed. + fn needs_reevaluation(self, opaques: usize, pseudo_rigid_bounds: usize) -> bool; } pub trait BoundVarKinds: diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 244d0ebf8210e..c1d7bdd8ce878 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -129,16 +129,16 @@ pub trait Interner: data: &[(ty::OpaqueTypeKey, Self::Ty)], ) -> Self::PredefinedOpaques; - type OpaqueHiddenTyBounds: Copy + type PseudoRigidDueToOpaquesBounds: Copy + Debug + Hash + Eq + TypeFoldable - + SliceLike)>; - fn mk_opaque_hidden_ty_bounds_in_body( + + SliceLike)>; + fn mk_pseudo_rigid_due_to_opaques_bounds_in_body( self, - data: &[(Self::Ty, ty::OpaqueHiddenTyBound)], - ) -> Self::OpaqueHiddenTyBounds; + data: &[(Self::Ty, ty::PseudoRigidDueToOpaquesBound)], + ) -> Self::PseudoRigidDueToOpaquesBounds; type LocalDefIds: Copy + Debug diff --git a/compiler/rustc_type_ir/src/opaque_ty.rs b/compiler/rustc_type_ir/src/opaque_ty.rs index a2d6a09ede5e8..7f89d99f0cae2 100644 --- a/compiler/rustc_type_ir/src/opaque_ty.rs +++ b/compiler/rustc_type_ir/src/opaque_ty.rs @@ -53,22 +53,24 @@ impl OpaqueTypeKey { } } -/// An item self bound for a hidden type(either an opaque or projection onto another hidden type). -/// This is meant to be instantiated inside the solver into an assumption for a goal with the goal's -/// self ty to support non-defining usages. +/// When we are in a defining scope of an opaque type we consider either that opaque type +/// or (chains of) projection types on it as pseudo-rigid even though it is not fully +/// resolved into a rigid type yet, to support non-defining usages (e.g. method calls) of +/// them. We register item self bounds for such pseudo-rigid alias types when we try to +/// normalize them, with the form of this struct. #[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, StableHash_NoContext) )] -pub struct OpaqueHiddenTyBound { +pub struct PseudoRigidDueToOpaquesBound { bound: Binder, } -impl Eq for OpaqueHiddenTyBound {} +impl Eq for PseudoRigidDueToOpaquesBound {} -impl OpaqueHiddenTyBound { +impl PseudoRigidDueToOpaquesBound { /// Iterate through the item self bounds of a hidden type for either an opaque /// or a projection onto another hidden ty. pub fn iter_item_self_bounds_for_hidden_ty( @@ -92,7 +94,7 @@ impl OpaqueHiddenTyBound { .fold_with(&mut ReplaceSelfTyWithAnonBound::new(cx, alias)), I::BoundVarKinds::from_vars(cx, [ty::BoundVariableKind::Ty(ty::BoundTyKind::Anon)]), ); - OpaqueHiddenTyBound { bound } + PseudoRigidDueToOpaquesBound { bound } }) } @@ -111,11 +113,14 @@ impl OpaqueHiddenTyBound { /// } /// ``` /// - /// We need to prove `<{opaque} as IntoIterator>::IntoIter: Iterator` to select the - /// method `collect()` on it. But as the given bounds in the scope don't mention the - /// assoc type `IntoIterator::IntoIter` at all, we can't assemble a candidate for - /// that trait goal. So, we have manually conjure a bound for such unmentioned - /// projections. + /// We need to solve a projection goal `<{opaque} as IntoIterator>::IntoIter = ?x` to + /// infer the self type for a method call `collect()`. But as the given bounds in the + /// scope don't mention the assoc type `IntoIterator::IntoIter` at all, we just get an + /// ambiguous response with unconstrained infer var, from no candidate. This is rejected + /// for being a self type for a method call because we allow self type being an infer + /// var if and only if it's considered as a pseudo-rigid due to opaques, i.e. we have + /// a bound for it in opaque ty storage. + /// So we conjure up one via its method and register it to the sol pub fn opt_unmentioned_projection_bound( cx: I, existing_bounds: impl IntoIterator, @@ -153,11 +158,11 @@ impl OpaqueHiddenTyBound { bound.fold_with(&mut ReplaceSelfTyWithAnonBound::new(cx, proj.self_ty())), I::BoundVarKinds::from_vars(cx, [ty::BoundVariableKind::Ty(ty::BoundTyKind::Anon)]), ); - Some(OpaqueHiddenTyBound { bound }) + Some(PseudoRigidDueToOpaquesBound { bound }) } pub fn instantiate(self, cx: I, self_ty: I::Ty) -> I::Clause { - let OpaqueHiddenTyBound { bound } = self; + let PseudoRigidDueToOpaquesBound { bound } = self; debug_assert_eq!( bound.bound_vars().as_slice(), diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 8c5e247b25f70..1234c40c414df 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -456,7 +456,7 @@ pub enum GoalSource { pub struct QueryInput { pub goal: Goal, pub predefined_opaques_in_body: I::PredefinedOpaques, - pub hidden_types_of_opaques_in_body: I::OpaqueHiddenTyBounds, + pub pseudo_rigid_due_to_opaques_bounds_in_body: I::PseudoRigidDueToOpaquesBounds, } impl Eq for QueryInput {} @@ -634,7 +634,7 @@ impl ExternalRegionConstraints { pub struct ExternalConstraintsData { pub region_constraints: ExternalRegionConstraints, pub opaque_types: I::PredefinedOpaques, - pub opaque_hidden_ty_bounds: I::OpaqueHiddenTyBounds, + pub pseudo_rigid_due_to_opaques_bounds: I::PseudoRigidDueToOpaquesBounds, pub normalization_nested_goals: NestedNormalizationGoals, } @@ -650,7 +650,8 @@ impl ExternalConstraintsData { Self { region_constraints, opaque_types: cx.mk_predefined_opaques_in_body(&[]), - opaque_hidden_ty_bounds: cx.mk_opaque_hidden_ty_bounds_in_body(&[]), + pseudo_rigid_due_to_opaques_bounds: cx + .mk_pseudo_rigid_due_to_opaques_bounds_in_body(&[]), normalization_nested_goals: NestedNormalizationGoals::default(), } } @@ -659,12 +660,12 @@ impl ExternalConstraintsData { let ExternalConstraintsData { region_constraints, opaque_types, - opaque_hidden_ty_bounds, + pseudo_rigid_due_to_opaques_bounds, normalization_nested_goals, } = self; region_constraints.is_empty() && opaque_types.is_empty() - && opaque_hidden_ty_bounds.is_empty() + && pseudo_rigid_due_to_opaques_bounds.is_empty() && normalization_nested_goals.is_empty() } } diff --git a/tests/ui/traits/next-solver/opaques/non-defining-use-stall-on-no-actual-change-im-the-caller.rs b/tests/ui/traits/next-solver/opaques/non-defining-use-stall-on-no-actual-change-in-the-caller.rs similarity index 100% rename from tests/ui/traits/next-solver/opaques/non-defining-use-stall-on-no-actual-change-im-the-caller.rs rename to tests/ui/traits/next-solver/opaques/non-defining-use-stall-on-no-actual-change-in-the-caller.rs From 494c50f130338f997cb0245ac3fadd6b0c9e9aee Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Tue, 29 Sep 2026 16:58:14 +0000 Subject: [PATCH 03/12] Yet another review addressment --- compiler/rustc_hir_analysis/src/autoderef.rs | 2 +- .../rustc_hir_analysis/src/check/check.rs | 14 +- compiler/rustc_hir_typeck/src/callee.rs | 2 +- compiler/rustc_hir_typeck/src/method/probe.rs | 141 +++++++++--------- .../src/infer/canonical/query_response.rs | 15 +- compiler/rustc_infer/src/infer/context.rs | 4 +- compiler/rustc_infer/src/infer/mod.rs | 22 ++- .../rustc_infer/src/infer/opaque_types/mod.rs | 6 + .../src/infer/opaque_types/table.rs | 35 +++-- .../src/infer/snapshot/undo_log.rs | 2 +- compiler/rustc_middle/src/traits/query.rs | 4 +- compiler/rustc_middle/src/ty/context.rs | 10 +- .../src/ty/context/impl_interner.rs | 4 +- .../rustc_middle/src/ty/structural_impls.rs | 2 +- .../src/canonical/canonicalizer.rs | 36 ++--- .../src/canonical/mod.rs | 4 +- .../src/solve/assembly/mod.rs | 20 +-- .../src/solve/eval_ctxt/mod.rs | 10 +- .../src/solve/project_goals/opaque_types.rs | 26 ++-- .../src/solve/trait_goals.rs | 2 +- compiler/rustc_type_ir/src/infer_ctxt.rs | 2 +- compiler/rustc_type_ir/src/interner.rs | 2 +- compiler/rustc_type_ir/src/solve/mod.rs | 5 +- ...stall-on-no-actual-change-in-the-caller.rs | 4 +- 24 files changed, 190 insertions(+), 184 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 432eee866f4c8..5bd754feee325 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -74,7 +74,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { // opaque type and instead return `None` in `fn overloaded_deref_ty` if the // opaque does not have a `Deref` item-bound. if let &ty::Infer(ty::TyVar(vid)) = self.state.cur_ty.kind() - && !self.infcx.is_pseudo_rigid_due_to_opaques_modulo_sub_unification(vid) + && !self.infcx.is_pseudo_rigid_due_to_opaques(vid) { return None; } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 9f8426a3eeb4c..ab017fa3fd94b 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -429,13 +429,8 @@ fn check_opaque_meets_bounds<'tcx>( let _ = infcx.take_opaque_types(); Ok(()) } else { - let (opaques, pseudo_rigids) = infcx.take_opaque_types(); - debug_assert!( - pseudo_rigids.is_empty(), - "We don't track anything in `pseudo_rigids_due_to_opaques` with the old solver" - ); // Check that any hidden types found during wf checking match the hidden types that `type_of` sees. - for (mut key, mut ty) in opaques { + for (mut key, mut ty) in infcx.take_opaque_types_old_solver() { ty.ty = infcx.deeply_resolve_ignoring_regions(ty.ty); key = infcx.deeply_resolve_ignoring_regions(key); sanity_check_found_hidden_type(tcx, key, ty)?; @@ -2356,14 +2351,9 @@ pub(super) fn check_coroutine_obligations( } if !tcx.next_trait_solver_globally() { - let (opaques, pseudo_rigids) = infcx.take_opaque_types(); - debug_assert!( - pseudo_rigids.is_empty(), - "We don't track anything in `pseudo_rigids_due_to_opaques` with the old solver" - ); // Check that any hidden types found when checking these stalled coroutine obligations // are valid. - for (key, ty) in opaques { + for (key, ty) in infcx.take_opaque_types_old_solver() { let hidden_type = infcx.deeply_resolve_ignoring_regions(ty); let key = infcx.deeply_resolve_ignoring_regions(key); sanity_check_found_hidden_type(tcx, key, hidden_type)?; diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index fed5afda80d89..ee1c187f185f2 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -336,7 +336,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Infer(ty::TyVar(vid)) => { // If we end up with an inference variable which is not the hidden type of // an opaque, emit an error. - if !self.is_pseudo_rigid_due_to_opaques_modulo_sub_unification(vid) { + if !self.is_pseudo_rigid_due_to_opaques(vid) { self.type_must_be_known_at_this_point(autoderef.span(), adjusted_ty); return None; } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 278067fd56b72..66f56196fac84 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -418,8 +418,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { ty::List::empty() }; - let pseudo_rigid_due_to_opaques_bounds_in_body = if self.next_trait_solver() { - self.tcx.mk_pseudo_rigid_due_to_opaques_bounds_in_body_from_iter( + let pseudo_rigid_due_to_opaques_bounds = if self.next_trait_solver() { + self.tcx.mk_pseudo_rigid_due_to_opaques_bounds_from_iter( self.inner.borrow_mut().opaque_types().iter_pseudo_rigid_due_to_opaques_bounds(), ) } else { @@ -427,7 +427,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let value = query::MethodAutoderefSteps { predefined_opaques_in_body, - pseudo_rigid_due_to_opaques_bounds_in_body, + pseudo_rigid_due_to_opaques_bounds, self_ty, }; let query_input = self @@ -446,7 +446,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { infcx.instantiate_canonical(span, &query_input.canonical); let query::MethodAutoderefSteps { predefined_opaques_in_body: _, - pseudo_rigid_due_to_opaques_bounds_in_body: _, + pseudo_rigid_due_to_opaques_bounds: _, self_ty, } = value; debug!(?self_ty, ?query_input, "probe_op: Mode::Path"); @@ -458,7 +458,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty, prev_opaque_entries, ), - self_ty_is_pseudo_rigid_opaques: false, + self_ty_is_pseudo_rigid_due_to_opaques: false, autoderefs: 0, from_unsafe_deref: false, unsize: false, @@ -659,7 +659,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( value: query::MethodAutoderefSteps { predefined_opaques_in_body, - pseudo_rigid_due_to_opaques_bounds_in_body, + pseudo_rigid_due_to_opaques_bounds, self_ty, }, } = goal; @@ -682,7 +682,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( } } infcx.register_pseudo_rigid_due_to_opaques_in_storage_with_flattened( - pseudo_rigid_due_to_opaques_bounds_in_body, + pseudo_rigid_due_to_opaques_bounds, ); let prev_opaque_entries = infcx.inner.borrow_mut().opaque_types().num_entries(); @@ -691,7 +691,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( // infer var is not an opaque. let self_ty_is_pseudo_rigid_due_to_opaques = |ty: Ty<'_>| { if let &ty::Infer(ty::TyVar(vid)) = ty.kind() { - infcx.is_pseudo_rigid_due_to_opaques_modulo_sub_unification(vid) + infcx.is_pseudo_rigid_due_to_opaques(vid) } else { false } @@ -714,64 +714,67 @@ pub(crate) fn method_autoderef_steps<'tcx>( let mut reached_raw_pointer = false; let arbitrary_self_types_enabled = tcx.features().arbitrary_self_types() || tcx.features().arbitrary_self_types_pointers(); - let (mut steps, reached_recursion_limit): (Vec<_>, bool) = if arbitrary_self_types_enabled { - let reachable_via_deref = - autoderef_via_deref.by_ref().map(|_| true).chain(std::iter::repeat(false)); - - let mut autoderef_via_receiver = - Autoderef::new(infcx, param_env, hir::def_id::CRATE_DEF_ID, DUMMY_SP, self_ty) - .include_raw_pointers() - .use_receiver_trait() - .silence_errors(); - let steps = autoderef_via_receiver - .by_ref() - .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, - prev_opaque_entries, - ), - self_ty_is_pseudo_rigid_opaques: self_ty_is_pseudo_rigid_due_to_opaques(ty), - autoderefs: d, - from_unsafe_deref: reached_raw_pointer, - unsize: false, - reachable_via_deref, - }; - if ty.is_raw_ptr() { - // all the subsequent steps will be from_unsafe_deref - reached_raw_pointer = true; - } - step - }) - .collect(); - (steps, autoderef_via_receiver.reached_recursion_limit()) - } else { - let steps = autoderef_via_deref - .by_ref() - .map(|(ty, d)| { - let step = CandidateStep { - self_ty: infcx.make_query_response_ignoring_pending_obligations( - inference_vars, - ty, - prev_opaque_entries, - ), - self_ty_is_pseudo_rigid_opaques: self_ty_is_pseudo_rigid_due_to_opaques(ty), - autoderefs: d, - from_unsafe_deref: reached_raw_pointer, - unsize: false, - reachable_via_deref: true, - }; - if ty.is_raw_ptr() { - // all the subsequent steps will be from_unsafe_deref - reached_raw_pointer = true; - } - step - }) - .collect(); - (steps, autoderef_via_deref.reached_recursion_limit()) - }; + let (mut steps, reached_recursion_limit): (Vec<_>, bool) = + if arbitrary_self_types_enabled { + let reachable_via_deref = + autoderef_via_deref.by_ref().map(|_| true).chain(std::iter::repeat(false)); + + let mut autoderef_via_receiver = + Autoderef::new(infcx, param_env, hir::def_id::CRATE_DEF_ID, DUMMY_SP, self_ty) + .include_raw_pointers() + .use_receiver_trait() + .silence_errors(); + let steps = autoderef_via_receiver + .by_ref() + .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, + prev_opaque_entries, + ), + self_ty_is_pseudo_rigid_due_to_opaques: + self_ty_is_pseudo_rigid_due_to_opaques(ty), + autoderefs: d, + from_unsafe_deref: reached_raw_pointer, + unsize: false, + reachable_via_deref, + }; + if ty.is_raw_ptr() { + // all the subsequent steps will be from_unsafe_deref + reached_raw_pointer = true; + } + step + }) + .collect(); + (steps, autoderef_via_receiver.reached_recursion_limit()) + } else { + let steps = autoderef_via_deref + .by_ref() + .map(|(ty, d)| { + let step = CandidateStep { + self_ty: infcx.make_query_response_ignoring_pending_obligations( + inference_vars, + ty, + prev_opaque_entries, + ), + self_ty_is_pseudo_rigid_due_to_opaques: + self_ty_is_pseudo_rigid_due_to_opaques(ty), + autoderefs: d, + from_unsafe_deref: reached_raw_pointer, + unsize: false, + reachable_via_deref: true, + }; + if ty.is_raw_ptr() { + // all the subsequent steps will be from_unsafe_deref + reached_raw_pointer = true; + } + step + }) + .collect(); + (steps, autoderef_via_deref.reached_recursion_limit()) + }; let final_ty = autoderef_via_deref.final_ty(); let opt_bad_ty = match final_ty.kind() { ty::Infer(ty::TyVar(_)) if !self_ty_is_pseudo_rigid_due_to_opaques(final_ty) => { @@ -800,7 +803,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( Ty::new_slice(infcx.tcx, *elem_ty), prev_opaque_entries, ), - self_ty_is_pseudo_rigid_opaques: false, + self_ty_is_pseudo_rigid_due_to_opaques: false, autoderefs, // this could be from an unsafe deref if we had // a *mut/const [T; N] @@ -2339,10 +2342,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } - // Check whether any hidden type of opaque in the autoderef chain have been + // Check whether any pseudo-rigid type in the autoderef chain has been // constrained. for step in self.steps { - if step.self_ty_is_pseudo_rigid_opaques { + if step.self_ty_is_pseudo_rigid_due_to_opaques { debug!(?step.autoderefs, ?step.self_ty, "self_type_is_opaque"); let constrained_opaque = self.probe(|_| { // If we fail to instantiate the self type of this diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index c3a25e19d898e..9468eb40b9423 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -155,14 +155,13 @@ impl<'tcx> InferCtxt<'tcx> { }); debug!(?region_constraints); - let opaque_types = self - .inner - .borrow_mut() - .opaque_type_storage - .take_opaque_types() - .0 - .map(|(k, v)| (k, v.ty)) - .collect(); + let mut inner = self.inner.borrow_mut(); + let (opaque_types, mut pseudo_rigids) = inner.opaque_type_storage.take_opaque_types(); + let opaque_types = opaque_types.map(|(k, v)| (k, v.ty)).collect(); + + // We register pseudo-rigid types only during HIR typeck, with the next-solver, + // and we shouldn't call the old solver style canonical queries there. + debug_assert!(pseudo_rigids.next().is_none()); Ok(QueryResponse { var_values: inference_vars, diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 0adebe316362d..9ef103fc6c812 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -375,11 +375,11 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { .pseudo_rigid_due_to_opaques_bounds_added_since(prev_entries) .collect() } - fn pseudo_rigids_due_to_opaques_modulo_sub_unification( + fn pseudo_rigids_due_to_opaques( &self, ty_vid: ty::TyVid, ) -> Vec<(Ty<'tcx>, Vec>)> { - self.pseudo_rigids_due_to_opaques_modulo_self_unification(ty_vid) + self.pseudo_rigids_due_to_opaques(ty_vid) } fn register_hidden_type_in_storage( diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 957b29f5b2cd6..b6a15d09ed17e 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1125,8 +1125,22 @@ impl<'tcx> InferCtxt<'tcx> { Vec<(Ty<'tcx>, FxIndexSet>)>, ) { let mut inner = self.inner.borrow_mut(); - let (opaques, hiddens) = inner.opaque_type_storage.take_opaque_types(); - (opaques.collect(), hiddens.collect()) + let (opaques, pseudo_rigids) = inner.opaque_type_storage.take_opaque_types(); + (opaques.collect(), pseudo_rigids.collect()) + } + + #[instrument(level = "debug", skip(self), ret)] + pub fn take_opaque_types_old_solver( + &self, + ) -> Vec<(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)> { + assert!(!self.next_trait_solver()); + let mut inner = self.inner.borrow_mut(); + let (opaques, mut pseudo_rigids) = inner.opaque_type_storage.take_opaque_types(); + debug_assert!( + pseudo_rigids.next().is_none(), + "We don't track any pseudo-rigids with the old solver" + ); + opaques.collect() } #[instrument(level = "debug", skip(self), ret)] @@ -1137,7 +1151,7 @@ impl<'tcx> InferCtxt<'tcx> { /// In the next solver, we normalize alias types by replacing them with infer vars and /// registering/evaluating projection goals /// They often but when we are in the defining scope of an opaque type and we haven't fully - pub fn is_pseudo_rigid_due_to_opaques_modulo_sub_unification(&self, ty_vid: TyVid) -> bool { + pub fn is_pseudo_rigid_due_to_opaques(&self, ty_vid: TyVid) -> bool { if !self.next_trait_solver() { return false; } @@ -1194,7 +1208,7 @@ impl<'tcx> InferCtxt<'tcx> { .collect() } - pub fn pseudo_rigids_due_to_opaques_modulo_self_unification( + pub fn pseudo_rigids_due_to_opaques( &self, ty_vid: TyVid, ) -> Vec<(Ty<'tcx>, Vec>)> { diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 9ec2f2f6955a5..2725691d6288f 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -8,6 +8,7 @@ use rustc_middle::ty::{ TypeVisitableExt, Unnormalized, }; use rustc_span::{Span, bug}; +use smallvec::SmallVec; use tracing::{debug, instrument}; use super::{DefineOpaqueTypes, RegionVariableOrigin}; @@ -212,6 +213,8 @@ impl<'tcx> InferCtxt<'tcx> { pseudo_rigid: Ty<'tcx>, bounds: impl IntoIterator>, ) { + assert!(self.next_trait_solver()); + let ty::Infer(ty::TyVar(vid)) = *pseudo_rigid.kind() else { return; }; @@ -219,6 +222,9 @@ impl<'tcx> InferCtxt<'tcx> { return; } + let bounds: SmallVec<[_; 8]> = + bounds.into_iter().map(|bound| self.deeply_resolve_ignoring_regions(bound)).collect(); + let ty_sub_vid = self.sub_unification_table_root_var(vid); let inner = &mut *self.inner.borrow_mut(); // This is iffy, can't call `type_variables()` as we're already diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index 2054669540146..f11a3af47093e 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -14,16 +14,21 @@ use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog}; pub struct OpaqueTypeStorage<'tcx> { opaque_types: FxIndexMap, ProvisionalHiddenType<'tcx>>, duplicate_entries: Vec<(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)>, - /// Note: - /// ```text - /// PseudoRigid ::= OpaqueTy - /// | Projection(::AssocTy), - /// where PseudoRigid: Trait is from PseudoRigid's bound - /// ``` + /// We define and register unresolved infer vars as *pseudo-rigid* types and there bounds + /// in the following, recursive manner: /// - /// When we normalize a `PseudoRigid`, we store its self-bounds here, to support non-defining - /// usages of sucu hidden types. The key is an expected term for the normalization and the value - /// is those self-bounds. + /// - Opaque types are pseudo-rigids in their defining scopes. We register their item-self + /// bounds along with them, e.g., if we have `impl Iterator`, the bounds are + /// `?pseudo-rigid: Iterator` and `::Item = i32`. + /// - When we assemble candidates for a goal whose self-ty is pseudo-rigid, we match those + /// bounds for that pseudo-rigid with the goal. + /// - From the above case, when we normalize an associated type whose self-ty is pseudo-rigid, + /// and the relevant candidate is one of those pseudo-rigid bounds, we register that + /// projection term as a new pseudo-rigid, along with the self-bounds for that associated + /// type. + /// + /// We consider those registered unresolved infer vars as pseudo-rigid and allow them to be + /// used in some of the non-defining usages such as being a self-type in a method call. pseudo_rigids_due_to_opaques: FxIndexMap, FxIndexSet>>, /// The flattened version of the above `pseudo_rigids_due_to_opaques`. This is a pure duplication @@ -77,21 +82,21 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { assert!(entry.is_some()); } - pub(crate) fn truncate_pseudo_rigids_due_to_opaques( + pub(crate) fn undo_pseudo_rigid_due_to_opaques( &mut self, - hidden_ty: Ty<'tcx>, + pseudo_rigid: Ty<'tcx>, len: Option, ) { let removed = if let Some(len) = len { - let bounds = self.pseudo_rigids_due_to_opaques.get_mut(&hidden_ty).unwrap(); + let bounds = self.pseudo_rigids_due_to_opaques.get_mut(&pseudo_rigid).unwrap(); let removed = bounds.len() - len; bounds.truncate(len); removed } else { - match self.pseudo_rigids_due_to_opaques.swap_remove(&hidden_ty) { + match self.pseudo_rigids_due_to_opaques.swap_remove(&pseudo_rigid) { None => bug!( "reverted pseudo-rigid type inference that was never registered: {:?}", - hidden_ty + pseudo_rigid ), Some(bounds) => bounds.len(), } @@ -101,7 +106,7 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { debug_assert!( (&self.pseudo_rigid_due_to_opaques_bounds[truncate_to..]) .iter() - .all(|(h, _)| *h == hidden_ty) + .all(|(pr, _)| *pr == pseudo_rigid) ); self.pseudo_rigid_due_to_opaques_bounds.truncate(truncate_to); } diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs index 85b8b81d7347f..b4ac74b873837 100644 --- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs +++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs @@ -69,7 +69,7 @@ impl<'tcx> Rollback> for InferCtxtInner<'tcx> { UndoLog::DuplicateOpaqueType => self.opaque_type_storage.pop_duplicate_entry(), UndoLog::OpaqueTypes(key, idx) => self.opaque_type_storage.remove(key, idx), UndoLog::PseudoRigidDueToOpaques(ty, len) => { - self.opaque_type_storage.truncate_pseudo_rigids_due_to_opaques(ty, len) + self.opaque_type_storage.undo_pseudo_rigid_due_to_opaques(ty, len) } UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo), UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo), diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 61e30042da075..de2bed6e3d50f 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -70,7 +70,7 @@ pub struct MethodAutoderefSteps<'tcx> { /// /// Only used by the new solver for now. pub predefined_opaques_in_body: solve::PredefinedOpaques<'tcx>, - pub pseudo_rigid_due_to_opaques_bounds_in_body: solve::PseudoRigidDueToOpaquesBounds<'tcx>, + pub pseudo_rigid_due_to_opaques_bounds: solve::PseudoRigidDueToOpaquesBounds<'tcx>, pub self_ty: Ty<'tcx>, } @@ -156,7 +156,7 @@ impl<'tcx> FromIterator> for DropckConstraint<'tcx> { #[derive(Debug, StableHash)] pub struct CandidateStep<'tcx> { pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, - pub self_ty_is_pseudo_rigid_opaques: bool, + pub self_ty_is_pseudo_rigid_due_to_opaques: bool, pub autoderefs: usize, /// `true` if the type results from a dereference of a raw pointer. /// when assembling candidates, we include these steps, but not when diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 1760d1326b814..36a2e0134e9fa 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -159,7 +159,7 @@ pub struct CtxtInterners<'tcx> { adt_def: InternedSet<'tcx, AdtDefData>, external_constraints: InternedSet<'tcx, ExternalConstraintsData>>, predefined_opaques_in_body: InternedSet<'tcx, List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>>, - pseudo_rigid_due_to_opaques_bounds_in_body: + pseudo_rigid_due_to_opaques_bounds: InternedSet<'tcx, List<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)>>, fields: InternedSet<'tcx, List>, local_def_ids: InternedSet<'tcx, List>, @@ -200,7 +200,7 @@ impl<'tcx> CtxtInterners<'tcx> { adt_def: InternedSet::with_capacity(N), external_constraints: InternedSet::with_capacity(N), predefined_opaques_in_body: InternedSet::with_capacity(N), - pseudo_rigid_due_to_opaques_bounds_in_body: InternedSet::with_capacity(N * 2), + pseudo_rigid_due_to_opaques_bounds: InternedSet::with_capacity(N * 2), fields: InternedSet::with_capacity(N * 4), local_def_ids: InternedSet::with_capacity(N), captures: InternedSet::with_capacity(N), @@ -2066,7 +2066,7 @@ slice_interners!( patterns: pub mk_patterns(Pattern<'tcx>), outlives: pub mk_outlives(ty::ArgOutlivesClause<'tcx>), predefined_opaques_in_body: pub mk_predefined_opaques_in_body((ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)), - pseudo_rigid_due_to_opaques_bounds_in_body: pub mk_pseudo_rigid_due_to_opaques_bounds_in_body((Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)), + pseudo_rigid_due_to_opaques_bounds: pub mk_pseudo_rigid_due_to_opaques_bounds((Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)), ); impl<'tcx> TyCtxt<'tcx> { @@ -2562,7 +2562,7 @@ impl<'tcx> TyCtxt<'tcx> { T::collect_and_apply(iter, |xs| self.mk_predefined_opaques_in_body(xs)) } - pub fn mk_pseudo_rigid_due_to_opaques_bounds_in_body_from_iter(self, iter: I) -> T::Output + pub fn mk_pseudo_rigid_due_to_opaques_bounds_from_iter(self, iter: I) -> T::Output where I: Iterator, T: CollectAndApply< @@ -2570,7 +2570,7 @@ impl<'tcx> TyCtxt<'tcx> { PseudoRigidDueToOpaquesBounds<'tcx>, >, { - T::collect_and_apply(iter, |xs| self.mk_pseudo_rigid_due_to_opaques_bounds_in_body(xs)) + T::collect_and_apply(iter, |xs| self.mk_pseudo_rigid_due_to_opaques_bounds(xs)) } pub fn mk_clauses_from_iter(self, iter: I) -> T::Output diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index c25f5578f8e1d..66eb85c91967b 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -78,11 +78,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type PseudoRigidDueToOpaquesBounds = solve::PseudoRigidDueToOpaquesBounds<'tcx>; - fn mk_pseudo_rigid_due_to_opaques_bounds_in_body( + fn mk_pseudo_rigid_due_to_opaques_bounds( self, data: &[(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)], ) -> Self::PseudoRigidDueToOpaquesBounds { - self.mk_pseudo_rigid_due_to_opaques_bounds_in_body(data) + self.mk_pseudo_rigid_due_to_opaques_bounds(data) } type LocalDefIds = &'tcx ty::List; diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 1279ddcbbdf02..492996a55048b 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -760,7 +760,7 @@ macro_rules! list_fold { list_fold! { &'tcx ty::List> : mk_poly_existential_predicates, &'tcx ty::List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>: mk_predefined_opaques_in_body, - &'tcx ty::List<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)>: mk_pseudo_rigid_due_to_opaques_bounds_in_body, + &'tcx ty::List<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)>: mk_pseudo_rigid_due_to_opaques_bounds, &'tcx ty::List> : mk_place_elems, &'tcx ty::List> : mk_patterns, &'tcx ty::List> : mk_outlives, diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 69d8d425434a9..586ddc4c4a861 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -148,9 +148,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { opaque_types: delegate.cx().mk_predefined_opaques_in_body(&opaque_types), pseudo_rigid_due_to_opaques_bounds: delegate .cx() - .mk_pseudo_rigid_due_to_opaques_bounds_in_body( - &pseudo_rigid_due_to_opaques_bounds, - ), + .mk_pseudo_rigid_due_to_opaques_bounds(&pseudo_rigid_due_to_opaques_bounds), normalization_nested_goals, }), }; @@ -286,21 +284,17 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { predefined_opaques_in_body }; - let pseudo_rigid_due_to_opaques_bounds_in_body = rest_canonicalizer + let pseudo_rigid_due_to_opaques_bounds = rest_canonicalizer .filter_and_canonicalize_pseudo_rigids_due_to_opaques_bounds( - input.pseudo_rigid_due_to_opaques_bounds_in_body.to_vec(), + input.pseudo_rigid_due_to_opaques_bounds.to_vec(), ); - let pseudo_rigid_due_to_opaques_bounds_in_body = - delegate.cx().mk_pseudo_rigid_due_to_opaques_bounds_in_body( - &pseudo_rigid_due_to_opaques_bounds_in_body, - ); + let pseudo_rigid_due_to_opaques_bounds = delegate + .cx() + .mk_pseudo_rigid_due_to_opaques_bounds(&pseudo_rigid_due_to_opaques_bounds); - let value = QueryInput { - goal, - predefined_opaques_in_body, - pseudo_rigid_due_to_opaques_bounds_in_body, - }; + let value = + QueryInput { goal, predefined_opaques_in_body, pseudo_rigid_due_to_opaques_bounds }; debug_assert!(!value.has_infer(), "unexpected infer in {value:?}"); debug_assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); @@ -497,7 +491,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { &mut self, mut pseudo_rigid_due_to_opaques_bounds: Vec<(I::Ty, ty::PseudoRigidDueToOpaquesBound)>, ) -> Vec<(I::Ty, ty::PseudoRigidDueToOpaquesBound)> { - let mut filtered = vec![]; + let mut res = vec![]; // This should be done in fixed-point iteration, because we may have some pseudo-rigid // that sub-unified with an infer var in another one's bounds. @@ -507,26 +501,26 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { // appears nowhere in preexisting `var_values` when we check it, but it becomes relevant // after we check and canonicalize the second one. while !pseudo_rigid_due_to_opaques_bounds.is_empty() { - let prev_len = filtered.len(); - pseudo_rigid_due_to_opaques_bounds.retain(|bounds @ (hidden_ty, _)| { - if let ty::Infer(ty::TyVar(vid)) = hidden_ty.kind() + let prev_len = res.len(); + pseudo_rigid_due_to_opaques_bounds.retain(|entry @ (pseudo_rigid, _)| { + if let ty::Infer(ty::TyVar(vid)) = pseudo_rigid.kind() && self .state .sub_root_lookup_table .contains_key(&self.delegate.sub_unification_table_root_var(vid)) { - filtered.push(bounds.clone().fold_with(self)); + res.push((*entry).fold_with(self)); false } else { true } }); - if filtered.len() == prev_len { + if res.len() == prev_len { break; } } - filtered + res } } diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index 280f1ed3ccc35..7f95e86e49761 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -69,9 +69,9 @@ where QueryInput { goal, predefined_opaques_in_body: delegate.cx().mk_predefined_opaques_in_body(opaque_types), - pseudo_rigid_due_to_opaques_bounds_in_body: delegate + pseudo_rigid_due_to_opaques_bounds: delegate .cx() - .mk_pseudo_rigid_due_to_opaques_bounds_in_body(pseudo_rigid_due_to_opaques_bounds), + .mk_pseudo_rigid_due_to_opaques_bounds(pseudo_rigid_due_to_opaques_bounds), }, ); diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index eb993d0eb5914..ee66bcd83fcd0 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -1157,9 +1157,8 @@ where if let Some(ty::NormalizesTo { alias, term }) = G::as_normalizes_to(goal.predicate) && let ty::AliasTermKind::ProjectionTy { def_id } = alias.kind - && ecx.typing_mode().should_register_pseudo_rigids_due_to_opaques() { - ecx.add_hidden_type_of_opaque_in_storage( + ecx.register_pseudo_rigid_due_to_opaques_in_storage( term.expect_ty(), ty::PseudoRigidDueToOpaquesBound::iter_item_self_bounds_for_hidden_ty( cx, @@ -1181,10 +1180,8 @@ where let self_ty = goal.predicate.self_ty(); // We only use this hack during HIR typeck. - let hidden_tys_of_opaques = match self.typing_mode() { - TypingMode::Typeck { .. } => { - self.pseudo_rigids_due_to_opaques_modulo_sub_unification(self_ty) - } + let pseudo_rigids = match self.typing_mode() { + TypingMode::Typeck { .. } => self.pseudo_rigids_due_to_opaques(self_ty), TypingMode::Coherence | TypingMode::PostTypeckUntilBorrowck { .. } | TypingMode::PostBorrowck { .. } @@ -1198,13 +1195,13 @@ where } }; - if hidden_tys_of_opaques.is_empty() { + if pseudo_rigids.is_empty() { candidates.extend(self.forced_ambiguity(MaybeInfo::AMBIGUOUS)); return Ok(()); } - for (hidden_ty, bounds) in &hidden_tys_of_opaques { - debug!("self ty is sub unified with {hidden_ty:?}"); + for (pseudo_rigid, bounds) in &pseudo_rigids { + debug!("self ty is sub unified with {pseudo_rigid:?}"); // We look at all item-bounds of the type being pseudo rigid due to opaques, // instantiating the self type of the bound with the current self @@ -1218,7 +1215,7 @@ where } } - // This is rather hacky and unprincipled, but we nee this anyway :( + // This is rather hacky and unprincipled, but we need this anyway :( // See the comments on // `[ty::PseudoRigidDueToOpaquesBound::opt_unmentioned_projection_bound]` // for details. @@ -1229,11 +1226,10 @@ where && let Some(unmentioned) = ty::PseudoRigidDueToOpaquesBound::opt_unmentioned_projection_bound( self.cx(), - hidden_tys_of_opaques.into_iter().flat_map(|(_, bounds)| bounds), + pseudo_rigids.into_iter().flat_map(|(_, bounds)| bounds), ty::ProjectionClause { projection_term: alias, term }, ) { - self.add_hidden_type_of_opaque_in_storage(goal.predicate.self_ty(), [unmentioned]); candidates.extend(consider_pseudo_rigid_due_to_opaques_bound(self, goal, unmentioned)); } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index f274ceb5ea4be..38940adeefc5b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -547,7 +547,7 @@ where } delegate.register_pseudo_rigid_due_to_opaques_in_storage_with_flattened( - input.pseudo_rigid_due_to_opaques_bounds_in_body.as_slice(), + input.pseudo_rigid_due_to_opaques_bounds.as_slice(), ); let initial_opaque_types_storage_num_entries = delegate.opaque_types_storage_num_entries(); @@ -1001,7 +1001,7 @@ where let num_opaques_in_storage = canonical_goal.canonical.value.predefined_opaques_in_body.len(); let num_hidden_ty_bounds_in_storage = - canonical_goal.canonical.value.pseudo_rigid_due_to_opaques_bounds_in_body.len(); + canonical_goal.canonical.value.pseudo_rigid_due_to_opaques_bounds.len(); GoalStalledOn { stalled_vars, @@ -1523,7 +1523,7 @@ where self.delegate.register_hidden_type_in_storage(opaque_type_key, hidden_ty, self.origin_span) } - pub(super) fn add_hidden_type_of_opaque_in_storage( + pub(super) fn register_pseudo_rigid_due_to_opaques_in_storage( &self, hidden_ty: I::Ty, bounds: impl IntoIterator>, @@ -1643,12 +1643,12 @@ where Ok(may_use_unstable_feature(&**self.delegate, param_env, symbol)) } - pub(crate) fn pseudo_rigids_due_to_opaques_modulo_sub_unification( + pub(crate) fn pseudo_rigids_due_to_opaques( &self, self_ty: I::Ty, ) -> Vec<(I::Ty, Vec>)> { if let ty::Infer(ty::TyVar(vid)) = self_ty.kind() { - self.delegate.pseudo_rigids_due_to_opaques_modulo_sub_unification(vid) + self.delegate.pseudo_rigids_due_to_opaques(vid) } else { vec![] } diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs index f011bd865293c..37e1ea33a32f3 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs @@ -88,7 +88,19 @@ where // inference variables. In borrowck we instead use the type // computed in HIR typeck as the initial value. match self.typing_mode().assert_not_erased() { - TypingMode::Typeck { .. } => {} + TypingMode::Typeck { .. } => { + self.register_pseudo_rigid_due_to_opaques_in_storage( + expected, + ty::PseudoRigidDueToOpaquesBound::iter_item_self_bounds_for_hidden_ty( + cx, + ty::AliasTy::new_from_args( + cx, + ty::AliasTyKind::Opaque { def_id: def_id.into() }, + normalized_args, + ), + ), + ); + } TypingMode::PostTypeckUntilBorrowck { .. } => { let actual = cx .type_of_opaque_hir_typeck(def_id) @@ -109,18 +121,6 @@ where | TypingMode::Reflection | TypingMode::Codegen => unreachable!(), } - - self.add_hidden_type_of_opaque_in_storage( - expected, - ty::PseudoRigidDueToOpaquesBound::iter_item_self_bounds_for_hidden_ty( - cx, - ty::AliasTy::new_from_args( - cx, - ty::AliasTyKind::Opaque { def_id: def_id.into() }, - normalized_args, - ), - ), - ); } self.add_item_bounds_for_hidden_type( diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index e1e87a3ffc1a3..5cb2110e0550a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -1327,7 +1327,7 @@ where // inference state. This is safe after typeck, where hidden types are already // fixed and only regions are inferred, but not during typeck while hidden // types may still contain inference variables. - if !opaque_types.is_empty() || !pseudo_rigid_due_to_opaques_bounds.is_empty() { + if !(opaque_types.is_empty() && pseudo_rigid_due_to_opaques_bounds.is_empty()) { let typing_mode = self.typing_mode(); match typing_mode { diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index e0f380c4a3e60..98ec65f372954 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -578,7 +578,7 @@ pub trait InferCtxtLike: Sized { &self, prev_entries: Self::OpaqueTypeStorageEntries, ) -> Vec<(::Ty, ty::PseudoRigidDueToOpaquesBound)>; - fn pseudo_rigids_due_to_opaques_modulo_sub_unification( + fn pseudo_rigids_due_to_opaques( &self, ty_vid: TyVid, ) -> Vec<( diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index c1d7bdd8ce878..3cc3f39d67516 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -135,7 +135,7 @@ pub trait Interner: + Eq + TypeFoldable + SliceLike)>; - fn mk_pseudo_rigid_due_to_opaques_bounds_in_body( + fn mk_pseudo_rigid_due_to_opaques_bounds( self, data: &[(Self::Ty, ty::PseudoRigidDueToOpaquesBound)], ) -> Self::PseudoRigidDueToOpaquesBounds; diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 1234c40c414df..b303dc3009100 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -456,7 +456,7 @@ pub enum GoalSource { pub struct QueryInput { pub goal: Goal, pub predefined_opaques_in_body: I::PredefinedOpaques, - pub pseudo_rigid_due_to_opaques_bounds_in_body: I::PseudoRigidDueToOpaquesBounds, + pub pseudo_rigid_due_to_opaques_bounds: I::PseudoRigidDueToOpaquesBounds, } impl Eq for QueryInput {} @@ -650,8 +650,7 @@ impl ExternalConstraintsData { Self { region_constraints, opaque_types: cx.mk_predefined_opaques_in_body(&[]), - pseudo_rigid_due_to_opaques_bounds: cx - .mk_pseudo_rigid_due_to_opaques_bounds_in_body(&[]), + pseudo_rigid_due_to_opaques_bounds: cx.mk_pseudo_rigid_due_to_opaques_bounds(&[]), normalization_nested_goals: NestedNormalizationGoals::default(), } } diff --git a/tests/ui/traits/next-solver/opaques/non-defining-use-stall-on-no-actual-change-in-the-caller.rs b/tests/ui/traits/next-solver/opaques/non-defining-use-stall-on-no-actual-change-in-the-caller.rs index 6f6803e622c60..d77f810c81042 100644 --- a/tests/ui/traits/next-solver/opaques/non-defining-use-stall-on-no-actual-change-in-the-caller.rs +++ b/tests/ui/traits/next-solver/opaques/non-defining-use-stall-on-no-actual-change-in-the-caller.rs @@ -5,7 +5,7 @@ // This is rather an implementation-detail-related test. // -// We track self-bounds of opaque-hidden-types in the `InferCtxt` and pass them via both query +// We track self-bounds of pseudo rigid infers in the `InferCtxt` and pass them via both query // inputs and responses. We try to dedup them per eager resolving and structural equality but they // don't always work well, especially due to canonicalizations. // @@ -17,7 +17,7 @@ // again. // // This pathetic reevaluation never stops and until we hit the recursion limit and end up with an -// overflow. To prevent this, we simply check whether the number of opaque hidden ty bounds has +// overflow. To prevent this, we simply check whether the number of pseudo rigid bounds has // actually increased from the evaluation after instantiating the response from the callers side to // decide evaluation's `has_changed`. From b03213b1caacf889a4757049cdd21a1ad8a7f479 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 30 Sep 2026 11:37:24 +0200 Subject: [PATCH 04/12] remove FxIndexMap --- compiler/rustc_hir_typeck/src/method/probe.rs | 14 +- .../src/infer/canonical/query_response.rs | 28 ++- compiler/rustc_infer/src/infer/context.rs | 18 +- compiler/rustc_infer/src/infer/mod.rs | 22 +-- .../rustc_infer/src/infer/opaque_types/mod.rs | 2 +- .../src/infer/opaque_types/table.rs | 178 ++++++------------ .../src/infer/snapshot/undo_log.rs | 8 +- compiler/rustc_middle/src/traits/query.rs | 2 +- compiler/rustc_middle/src/traits/solve.rs | 14 +- compiler/rustc_middle/src/ty/context.rs | 14 +- .../src/ty/context/impl_interner.rs | 8 +- .../rustc_middle/src/ty/structural_impls.rs | 2 +- .../src/canonical/canonicalizer.rs | 34 ++-- .../src/canonical/mod.rs | 10 +- .../src/solve/assembly/mod.rs | 18 +- .../src/solve/eval_ctxt/mod.rs | 69 +++---- .../rustc_next_trait_solver/src/solve/mod.rs | 14 +- .../src/solve/trait_goals.rs | 4 +- compiler/rustc_type_ir/src/infer_ctxt.rs | 15 +- compiler/rustc_type_ir/src/interner.rs | 6 +- compiler/rustc_type_ir/src/solve/mod.rs | 10 +- 21 files changed, 207 insertions(+), 283 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 66f56196fac84..c594c46932aec 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -418,16 +418,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { ty::List::empty() }; - let pseudo_rigid_due_to_opaques_bounds = if self.next_trait_solver() { - self.tcx.mk_pseudo_rigid_due_to_opaques_bounds_from_iter( - self.inner.borrow_mut().opaque_types().iter_pseudo_rigid_due_to_opaques_bounds(), + let pseudo_rigid_due_to_opaques = if self.next_trait_solver() { + self.tcx.mk_pseudo_rigid_due_to_opaques_from_iter( + self.inner.borrow_mut().opaque_types().iter_pseudo_rigid_due_to_opaques(), ) } else { ty::List::empty() }; let value = query::MethodAutoderefSteps { predefined_opaques_in_body, - pseudo_rigid_due_to_opaques_bounds, + pseudo_rigid_due_to_opaques, self_ty, }; let query_input = self @@ -446,7 +446,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { infcx.instantiate_canonical(span, &query_input.canonical); let query::MethodAutoderefSteps { predefined_opaques_in_body: _, - pseudo_rigid_due_to_opaques_bounds: _, + pseudo_rigid_due_to_opaques: _, self_ty, } = value; debug!(?self_ty, ?query_input, "probe_op: Mode::Path"); @@ -659,7 +659,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( value: query::MethodAutoderefSteps { predefined_opaques_in_body, - pseudo_rigid_due_to_opaques_bounds, + pseudo_rigid_due_to_opaques, self_ty, }, } = goal; @@ -682,7 +682,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( } } infcx.register_pseudo_rigid_due_to_opaques_in_storage_with_flattened( - pseudo_rigid_due_to_opaques_bounds, + pseudo_rigid_due_to_opaques, ); let prev_opaque_entries = infcx.inner.borrow_mut().opaque_types().num_entries(); diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 9468eb40b9423..b867740a9614d 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -13,7 +13,9 @@ use std::iter; use rustc_index::{Idx, IndexVec}; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::infer::canonical::{CanonicalVarKind, QueryRegionConstraint}; -use rustc_middle::ty::{self, BoundVar, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{ + self, BoundVar, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypingMode, +}; use rustc_span::bug; use tracing::{debug, instrument}; @@ -156,12 +158,28 @@ impl<'tcx> InferCtxt<'tcx> { debug!(?region_constraints); let mut inner = self.inner.borrow_mut(); - let (opaque_types, mut pseudo_rigids) = inner.opaque_type_storage.take_opaque_types(); + let (opaque_types, pseudo_rigid) = inner.opaque_type_storage.take_opaque_types(); let opaque_types = opaque_types.map(|(k, v)| (k, v.ty)).collect(); - // We register pseudo-rigid types only during HIR typeck, with the next-solver, - // and we shouldn't call the old solver style canonical queries there. - debug_assert!(pseudo_rigids.next().is_none()); + // We don't handle `pseudo_rigid` correctly here, so make sure we never use old style + // canonical responses with the new solver in any place which may add any. + debug_assert!(pseudo_rigid.is_empty()); + if cfg!(debug_assertions) && self.next_trait_solver() { + match self.typing_mode_raw().assert_not_erased() { + TypingMode::Typeck { defining_opaque_types_and_generators } => { + assert!( + defining_opaque_types_and_generators.is_empty(), + "old style query response in new solver typeck", + ); + } + TypingMode::Coherence + | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostBorrowck { .. } + | TypingMode::PostAnalysis + | TypingMode::Reflection + | TypingMode::Codegen => {} + } + } Ok(QueryResponse { var_values: inference_vars, diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 9ef103fc6c812..e3a884266ef6c 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -343,16 +343,16 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { fn opaque_types_storage_num_entries(&self) -> OpaqueTypeStorageEntries { self.inner.borrow_mut().opaque_types().num_entries() } - fn num_pseudo_rigid_due_to_opaques_bounds(&self) -> usize { - self.inner.borrow_mut().opaque_types().num_pseudo_rigid_due_to_opaques_bounds() + fn num_pseudo_rigid_due_to_opaques(&self) -> usize { + self.inner.borrow_mut().opaque_types().num_pseudo_rigid_due_to_opaques() } fn clone_opaque_types_lookup_table(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { self.inner.borrow_mut().opaque_types().iter_lookup_table().map(|(k, h)| (k, h.ty)).collect() } - fn clone_pseudo_rigid_due_to_opaques_bounds( + fn clone_pseudo_rigid_due_to_opaques( &self, ) -> Vec<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)> { - self.inner.borrow_mut().opaque_types().iter_pseudo_rigid_due_to_opaques_bounds().collect() + self.inner.borrow_mut().opaque_types().iter_pseudo_rigid_due_to_opaques().collect() } fn clone_opaque_types_added_since( &self, @@ -365,21 +365,21 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { .map(|(k, h)| (k, h.ty)) .collect() } - fn clone_pseudo_rigid_due_to_opaques_bounds_added_since( + fn clone_pseudo_rigid_due_to_opaques_added_since( &self, prev_entries: OpaqueTypeStorageEntries, ) -> Vec<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)> { self.inner .borrow_mut() .opaque_types() - .pseudo_rigid_due_to_opaques_bounds_added_since(prev_entries) + .pseudo_rigid_due_to_opaques_added_since(prev_entries) .collect() } - fn pseudo_rigids_due_to_opaques( + fn pseudo_rigid_due_to_opaques( &self, ty_vid: ty::TyVid, - ) -> Vec<(Ty<'tcx>, Vec>)> { - self.pseudo_rigids_due_to_opaques(ty_vid) + ) -> Vec> { + self.pseudo_rigid_due_to_opaques(ty_vid) } fn register_hidden_type_in_storage( diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index b6a15d09ed17e..d786d89e3fedb 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -12,7 +12,7 @@ use region_constraints::{ GenericKind, RegionConstraintCollector, RegionConstraintStorage, VarInfos, VerifyBound, }; pub use relate::combine::PredicateEmittingRelation; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::undo_log::{Rollback, UndoLogs}; use rustc_data_structures::unify::{self as ut, UnifyKey, UnifyValue}; @@ -1122,11 +1122,11 @@ impl<'tcx> InferCtxt<'tcx> { &self, ) -> ( Vec<(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)>, - Vec<(Ty<'tcx>, FxIndexSet>)>, + Vec<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)>, ) { let mut inner = self.inner.borrow_mut(); let (opaques, pseudo_rigids) = inner.opaque_type_storage.take_opaque_types(); - (opaques.collect(), pseudo_rigids.collect()) + (opaques.collect(), pseudo_rigids) } #[instrument(level = "debug", skip(self), ret)] @@ -1135,9 +1135,9 @@ impl<'tcx> InferCtxt<'tcx> { ) -> Vec<(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)> { assert!(!self.next_trait_solver()); let mut inner = self.inner.borrow_mut(); - let (opaques, mut pseudo_rigids) = inner.opaque_type_storage.take_opaque_types(); + let (opaques, pseudo_rigids) = inner.opaque_type_storage.take_opaque_types(); debug_assert!( - pseudo_rigids.next().is_none(), + pseudo_rigids.is_empty(), "We don't track any pseudo-rigids with the old solver" ); opaques.collect() @@ -1159,7 +1159,7 @@ impl<'tcx> InferCtxt<'tcx> { let ty_sub_vid = self.sub_unification_table_root_var(ty_vid); let inner = &mut *self.inner.borrow_mut(); let mut type_variables = inner.type_variable_storage.with_log(&mut inner.undo_log); - inner.opaque_type_storage.iter_pseudo_rigids_due_to_opaques().any(|(hidden_ty, _)| { + inner.opaque_type_storage.iter_pseudo_rigid_due_to_opaques().any(|(hidden_ty, _)| { if let ty::Infer(ty::TyVar(hidden_vid)) = *hidden_ty.kind() { let opaque_sub_vid = type_variables.sub_unification_table_root_var(hidden_vid); if opaque_sub_vid == ty_sub_vid { @@ -1208,10 +1208,10 @@ impl<'tcx> InferCtxt<'tcx> { .collect() } - pub fn pseudo_rigids_due_to_opaques( + pub fn pseudo_rigid_due_to_opaques( &self, ty_vid: TyVid, - ) -> Vec<(Ty<'tcx>, Vec>)> { + ) -> Vec> { // Avoid accidentally allowing more code to compile with the old solver. if !self.next_trait_solver() { return vec![]; @@ -1224,12 +1224,12 @@ impl<'tcx> InferCtxt<'tcx> { let mut type_variables = inner.type_variable_storage.with_log(&mut inner.undo_log); inner .opaque_type_storage - .iter_pseudo_rigids_due_to_opaques() - .filter_map(|(pseudo_rigid, bounds)| { + .iter_pseudo_rigid_due_to_opaques() + .filter_map(|(pseudo_rigid, bound)| { if let ty::Infer(ty::TyVar(hidden_vid)) = *pseudo_rigid.kind() { let opaque_sub_vid = type_variables.sub_unification_table_root_var(hidden_vid); if opaque_sub_vid == ty_sub_vid { - return Some((pseudo_rigid, bounds.iter().copied().collect())); + return Some(bound); } } diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 2725691d6288f..f8c97cbe3c382 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -240,7 +240,7 @@ impl<'tcx> InferCtxt<'tcx> { // heuristics. let pseudo_rigid = inner .opaque_type_storage - .iter_pseudo_rigids_due_to_opaques() + .iter_pseudo_rigid_due_to_opaques() .map(|(pr, _)| pr) .find(|pr| { if let ty::Infer(ty::TyVar(ty_vid)) = *pr.kind() { diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index f11a3af47093e..62768f1dd0737 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -1,8 +1,6 @@ -use std::iter; use std::ops::Deref; -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::indexmap::map::Entry; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::undo_log::UndoLogs; use rustc_middle::ty::{self as ty, OpaqueTypeKey, ProvisionalHiddenType, Ty}; use rustc_span::bug; @@ -14,28 +12,20 @@ use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog}; pub struct OpaqueTypeStorage<'tcx> { opaque_types: FxIndexMap, ProvisionalHiddenType<'tcx>>, duplicate_entries: Vec<(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)>, - /// We define and register unresolved infer vars as *pseudo-rigid* types and there bounds - /// in the following, recursive manner: + /// We consider inference variables which are the hidden type of an opaque type or + /// an unconstrained associated type of an opaque as pseudo-rigid. A pseudo-rigid + /// inference variable is allowed as the self-type for method calls and we use the + /// item bounds of the opaque to incompletely guide inference. We define and register + /// unresolved infer vars as *pseudo-rigid* types and there bounds in the following, + /// recursive manner: /// - /// - Opaque types are pseudo-rigids in their defining scopes. We register their item-self + /// - The hidden types of opaques are pseudo-rigid. We register their item-self /// bounds along with them, e.g., if we have `impl Iterator`, the bounds are /// `?pseudo-rigid: Iterator` and `::Item = i32`. - /// - When we assemble candidates for a goal whose self-ty is pseudo-rigid, we match those - /// bounds for that pseudo-rigid with the goal. - /// - From the above case, when we normalize an associated type whose self-ty is pseudo-rigid, - /// and the relevant candidate is one of those pseudo-rigid bounds, we register that - /// projection term as a new pseudo-rigid, along with the self-bounds for that associated - /// type. - /// - /// We consider those registered unresolved infer vars as pseudo-rigid and allow them to be - /// used in some of the non-defining usages such as being a self-type in a method call. - pseudo_rigids_due_to_opaques: - FxIndexMap, FxIndexSet>>, - /// The flattened version of the above `pseudo_rigids_due_to_opaques`. This is a pure duplication - /// but we need this to track things linearly, so that we can track the number of those bounds - /// in [`OpaqueTypeStorageEntries`] without a map and can lookup `pseudo_rigid_due_to_opaques_bounds` - /// in O(1). - pseudo_rigid_due_to_opaques_bounds: Vec<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)>, + /// - When we normalize an associated type whose self-ty is pseudo-rigid, and there does + /// not exist a `Projection` clause for that associated type, we register the normalized-to + /// term as a new pseudo-rigid. This fixes trait-system-refactor-initiative#248. + pseudo_rigid_due_to_opaques: Vec<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)>, } /// The number of entries in the opaque type storage at a given point. @@ -46,17 +36,17 @@ pub struct OpaqueTypeStorage<'tcx> { pub struct OpaqueTypeStorageEntries { opaque_types: usize, duplicate_entries: usize, - pseudo_rigid_due_to_opaques_bounds: usize, + pseudo_rigid_due_to_opaques: usize, } impl rustc_type_ir::inherent::OpaqueTypeStorageEntries for OpaqueTypeStorageEntries { - fn needs_reevaluation(self, opaques: usize, pseudo_rigid_bounds: usize) -> bool { + fn needs_reevaluation(self, opaques: usize, pseudo_rigid: usize) -> bool { let OpaqueTypeStorageEntries { opaque_types, duplicate_entries: _, - pseudo_rigid_due_to_opaques_bounds, + pseudo_rigid_due_to_opaques, } = self; - opaques != opaque_types || pseudo_rigid_bounds != pseudo_rigid_due_to_opaques_bounds + opaques != opaque_types || pseudo_rigid != pseudo_rigid_due_to_opaques } } @@ -82,64 +72,34 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { assert!(entry.is_some()); } - pub(crate) fn undo_pseudo_rigid_due_to_opaques( - &mut self, - pseudo_rigid: Ty<'tcx>, - len: Option, - ) { - let removed = if let Some(len) = len { - let bounds = self.pseudo_rigids_due_to_opaques.get_mut(&pseudo_rigid).unwrap(); - let removed = bounds.len() - len; - bounds.truncate(len); - removed - } else { - match self.pseudo_rigids_due_to_opaques.swap_remove(&pseudo_rigid) { - None => bug!( - "reverted pseudo-rigid type inference that was never registered: {:?}", - pseudo_rigid - ), - Some(bounds) => bounds.len(), - } - }; - - let truncate_to = self.pseudo_rigid_due_to_opaques_bounds.len() - removed; - debug_assert!( - (&self.pseudo_rigid_due_to_opaques_bounds[truncate_to..]) - .iter() - .all(|(pr, _)| *pr == pseudo_rigid) - ); - self.pseudo_rigid_due_to_opaques_bounds.truncate(truncate_to); + pub(crate) fn undo_pseudo_rigid_due_to_opaques(&mut self, len: usize) { + debug_assert!(self.pseudo_rigid_due_to_opaques.len() > len); + self.pseudo_rigid_due_to_opaques.truncate(len); } pub fn is_empty(&self) -> bool { - let OpaqueTypeStorage { - opaque_types, - duplicate_entries, - pseudo_rigids_due_to_opaques, - pseudo_rigid_due_to_opaques_bounds, - } = self; - opaque_types.is_empty() - && duplicate_entries.is_empty() - && pseudo_rigids_due_to_opaques.is_empty() - && pseudo_rigid_due_to_opaques_bounds.is_empty() + let OpaqueTypeStorage { opaque_types, duplicate_entries, pseudo_rigid_due_to_opaques } = + self; + if opaque_types.is_empty() { + debug_assert!(duplicate_entries.is_empty()); + debug_assert!(pseudo_rigid_due_to_opaques.is_empty()); + true + } else { + false + } } pub(crate) fn take_opaque_types( &mut self, ) -> ( impl Iterator, ProvisionalHiddenType<'tcx>)>, - impl Iterator, FxIndexSet>)>, + Vec<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)>, ) { - let OpaqueTypeStorage { - opaque_types, - duplicate_entries, - pseudo_rigids_due_to_opaques, - pseudo_rigid_due_to_opaques_bounds, - } = self; - let _ = std::mem::take(pseudo_rigid_due_to_opaques_bounds); + let OpaqueTypeStorage { opaque_types, duplicate_entries, pseudo_rigid_due_to_opaques } = + self; ( std::mem::take(opaque_types).into_iter().chain(std::mem::take(duplicate_entries)), - std::mem::take(pseudo_rigids_due_to_opaques).into_iter(), + std::mem::take(pseudo_rigid_due_to_opaques), ) } @@ -147,12 +107,12 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { OpaqueTypeStorageEntries { opaque_types: self.opaque_types.len(), duplicate_entries: self.duplicate_entries.len(), - pseudo_rigid_due_to_opaques_bounds: self.pseudo_rigid_due_to_opaques_bounds.len(), + pseudo_rigid_due_to_opaques: self.pseudo_rigid_due_to_opaques.len(), } } - pub fn num_pseudo_rigid_due_to_opaques_bounds(&self) -> usize { - self.pseudo_rigid_due_to_opaques_bounds.len() + pub fn num_pseudo_rigid_due_to_opaques(&self) -> usize { + self.pseudo_rigid_due_to_opaques.len() } pub fn opaque_types_added_since( @@ -166,13 +126,13 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { .chain(self.duplicate_entries.iter().skip(prev_entries.duplicate_entries).copied()) } - pub fn pseudo_rigid_due_to_opaques_bounds_added_since( + pub fn pseudo_rigid_due_to_opaques_added_since( &self, prev_entries: OpaqueTypeStorageEntries, ) -> impl Iterator, ty::PseudoRigidDueToOpaquesBound<'tcx>)> { - self.pseudo_rigid_due_to_opaques_bounds + self.pseudo_rigid_due_to_opaques .iter() - .skip(prev_entries.pseudo_rigid_due_to_opaques_bounds) + .skip(prev_entries.pseudo_rigid_due_to_opaques) .copied() } @@ -201,37 +161,20 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { pub fn iter_opaque_types( &self, ) -> impl Iterator, ProvisionalHiddenType<'tcx>)> { - let OpaqueTypeStorage { - opaque_types, - duplicate_entries, - pseudo_rigids_due_to_opaques: _, - pseudo_rigid_due_to_opaques_bounds: _, - } = self; + let OpaqueTypeStorage { opaque_types, duplicate_entries, pseudo_rigid_due_to_opaques: _ } = + self; opaque_types.iter().map(|(k, v)| (*k, *v)).chain(duplicate_entries.iter().copied()) } - pub fn iter_pseudo_rigids_due_to_opaques( - &self, - ) -> impl Iterator, &FxIndexSet>)> { - let OpaqueTypeStorage { - opaque_types: _, - duplicate_entries: _, - pseudo_rigids_due_to_opaques, - pseudo_rigid_due_to_opaques_bounds: _, - } = self; - pseudo_rigids_due_to_opaques.iter().map(|(pr, bounds)| (*pr, bounds)) - } - - pub fn iter_pseudo_rigid_due_to_opaques_bounds( + pub fn iter_pseudo_rigid_due_to_opaques( &self, ) -> impl Iterator, ty::PseudoRigidDueToOpaquesBound<'tcx>)> { let OpaqueTypeStorage { opaque_types: _, duplicate_entries: _, - pseudo_rigids_due_to_opaques: _, - pseudo_rigid_due_to_opaques_bounds, + pseudo_rigid_due_to_opaques, } = self; - pseudo_rigid_due_to_opaques_bounds.iter().copied() + pseudo_rigid_due_to_opaques.iter().copied() } #[inline] @@ -289,32 +232,17 @@ impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> { let OpaqueTypeStorage { opaque_types: _, duplicate_entries: _, - pseudo_rigids_due_to_opaques, - pseudo_rigid_due_to_opaques_bounds, + pseudo_rigid_due_to_opaques, } = self.storage; - let prev_len = match pseudo_rigids_due_to_opaques.entry(pseudo_rigid) { - Entry::Occupied(mut entry) => { - let entry = entry.get_mut(); - let len = entry.len(); - entry.extend(bounds); - if entry.len() == len { - return; - } - pseudo_rigid_due_to_opaques_bounds - .extend(iter::repeat(pseudo_rigid).zip(entry.iter().skip(len).copied())); - Some(len) - } - Entry::Vacant(vacant) => { - let bounds: FxIndexSet<_> = bounds.into_iter().collect(); - if bounds.is_empty() { - return; - } - let entry = vacant.insert(bounds); - pseudo_rigid_due_to_opaques_bounds - .extend(iter::repeat(pseudo_rigid).zip(entry.iter().copied())); - None + let prev_len = pseudo_rigid_due_to_opaques.len(); + for bound in bounds { + if !pseudo_rigid_due_to_opaques.contains(&(pseudo_rigid, bound)) { + pseudo_rigid_due_to_opaques.push((pseudo_rigid, bound)); } - }; - self.undo_log.push(UndoLog::PseudoRigidDueToOpaques(pseudo_rigid, prev_len)); + } + + if prev_len != pseudo_rigid_due_to_opaques.len() { + self.undo_log.push(UndoLog::PseudoRigidDueToOpaques(prev_len)); + } } } diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs index b4ac74b873837..f98d32578081f 100644 --- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs +++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use rustc_data_structures::undo_log::{Rollback, UndoLogs}; use rustc_data_structures::{snapshot_vec as sv, unify as ut}; -use rustc_middle::ty::{self, OpaqueTypeKey, ProvisionalHiddenType, Ty}; +use rustc_middle::ty::{self, OpaqueTypeKey, ProvisionalHiddenType}; use tracing::debug; use crate::infer::unify_key::{ConstVidKey, RegionVidKey}; @@ -20,7 +20,7 @@ pub struct Snapshot<'tcx> { pub(crate) enum UndoLog<'tcx> { DuplicateOpaqueType, OpaqueTypes(OpaqueTypeKey<'tcx>, Option>), - PseudoRigidDueToOpaques(Ty<'tcx>, Option), + PseudoRigidDueToOpaques(usize), TypeVariables(type_variable::UndoLog<'tcx>), ConstUnificationTable(sv::UndoLog>>), IntUnificationTable(sv::UndoLog>), @@ -68,8 +68,8 @@ impl<'tcx> Rollback> for InferCtxtInner<'tcx> { match undo { UndoLog::DuplicateOpaqueType => self.opaque_type_storage.pop_duplicate_entry(), UndoLog::OpaqueTypes(key, idx) => self.opaque_type_storage.remove(key, idx), - UndoLog::PseudoRigidDueToOpaques(ty, len) => { - self.opaque_type_storage.undo_pseudo_rigid_due_to_opaques(ty, len) + UndoLog::PseudoRigidDueToOpaques(len) => { + self.opaque_type_storage.undo_pseudo_rigid_due_to_opaques(len) } UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo), UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo), diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index de2bed6e3d50f..a9a76a4b2be9f 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -70,7 +70,7 @@ pub struct MethodAutoderefSteps<'tcx> { /// /// Only used by the new solver for now. pub predefined_opaques_in_body: solve::PredefinedOpaques<'tcx>, - pub pseudo_rigid_due_to_opaques_bounds: solve::PseudoRigidDueToOpaquesBounds<'tcx>, + pub pseudo_rigid_due_to_opaques: solve::PseudoRigidDueToOpaques<'tcx>, pub self_ty: Ty<'tcx>, } diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 637a3719df37f..a29ff122361db 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -21,7 +21,7 @@ pub type GoalStalledOnOpaques<'tcx> = ir::solve::GoalStalledOnOpaques = ir::solve::SucceededInErased>; pub type PredefinedOpaques<'tcx> = &'tcx ty::List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>; -pub type PseudoRigidDueToOpaquesBounds<'tcx> = +pub type PseudoRigidDueToOpaques<'tcx> = &'tcx ty::List<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)>; // Interning CanonicalInput drastically reduces max memory usage when compiling a crate that has @@ -75,9 +75,7 @@ impl<'tcx> TypeFoldable> for ExternalConstraints<'tcx> { Ok(FallibleTypeFolder::cx(folder).mk_external_constraints(ExternalConstraintsData { region_constraints: self.region_constraints.clone().try_fold_with(folder)?, opaque_types: self.opaque_types.try_fold_with(folder)?, - pseudo_rigid_due_to_opaques_bounds: self - .pseudo_rigid_due_to_opaques_bounds - .try_fold_with(folder)?, + pseudo_rigid_due_to_opaques: self.pseudo_rigid_due_to_opaques.try_fold_with(folder)?, normalization_nested_goals: self .normalization_nested_goals .clone() @@ -96,9 +94,7 @@ impl<'tcx> TypeFoldable> for ExternalConstraints<'tcx> { TypeFolder::cx(folder).mk_external_constraints(ExternalConstraintsData { region_constraints: self.region_constraints.clone().fold_with(folder), opaque_types: self.opaque_types.fold_with(folder), - pseudo_rigid_due_to_opaques_bounds: self - .pseudo_rigid_due_to_opaques_bounds - .fold_with(folder), + pseudo_rigid_due_to_opaques: self.pseudo_rigid_due_to_opaques.fold_with(folder), normalization_nested_goals: self.normalization_nested_goals.clone().fold_with(folder), }) } @@ -109,13 +105,13 @@ impl<'tcx> TypeVisitable> for ExternalConstraints<'tcx> { let ExternalConstraintsData { region_constraints, opaque_types, - pseudo_rigid_due_to_opaques_bounds, + pseudo_rigid_due_to_opaques, normalization_nested_goals, } = &**self; try_visit!(region_constraints.visit_with(visitor)); try_visit!(opaque_types.visit_with(visitor)); - try_visit!(pseudo_rigid_due_to_opaques_bounds.visit_with(visitor)); + try_visit!(pseudo_rigid_due_to_opaques.visit_with(visitor)); normalization_nested_goals.visit_with(visitor) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 36a2e0134e9fa..5ed3939fa9097 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -66,7 +66,7 @@ use crate::thir::Thir; use crate::traits; use crate::traits::solve::{ CanonicalInput, CanonicalInputData, ExternalConstraints, ExternalConstraintsData, - PredefinedOpaques, PseudoRigidDueToOpaquesBounds, + PredefinedOpaques, PseudoRigidDueToOpaques, }; use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; use crate::ty::{ @@ -159,7 +159,7 @@ pub struct CtxtInterners<'tcx> { adt_def: InternedSet<'tcx, AdtDefData>, external_constraints: InternedSet<'tcx, ExternalConstraintsData>>, predefined_opaques_in_body: InternedSet<'tcx, List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>>, - pseudo_rigid_due_to_opaques_bounds: + pseudo_rigid_due_to_opaques: InternedSet<'tcx, List<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)>>, fields: InternedSet<'tcx, List>, local_def_ids: InternedSet<'tcx, List>, @@ -200,7 +200,7 @@ impl<'tcx> CtxtInterners<'tcx> { adt_def: InternedSet::with_capacity(N), external_constraints: InternedSet::with_capacity(N), predefined_opaques_in_body: InternedSet::with_capacity(N), - pseudo_rigid_due_to_opaques_bounds: InternedSet::with_capacity(N * 2), + pseudo_rigid_due_to_opaques: InternedSet::with_capacity(N * 2), fields: InternedSet::with_capacity(N * 4), local_def_ids: InternedSet::with_capacity(N), captures: InternedSet::with_capacity(N), @@ -2066,7 +2066,7 @@ slice_interners!( patterns: pub mk_patterns(Pattern<'tcx>), outlives: pub mk_outlives(ty::ArgOutlivesClause<'tcx>), predefined_opaques_in_body: pub mk_predefined_opaques_in_body((ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)), - pseudo_rigid_due_to_opaques_bounds: pub mk_pseudo_rigid_due_to_opaques_bounds((Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)), + pseudo_rigid_due_to_opaques: pub mk_pseudo_rigid_due_to_opaques((Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)), ); impl<'tcx> TyCtxt<'tcx> { @@ -2562,15 +2562,15 @@ impl<'tcx> TyCtxt<'tcx> { T::collect_and_apply(iter, |xs| self.mk_predefined_opaques_in_body(xs)) } - pub fn mk_pseudo_rigid_due_to_opaques_bounds_from_iter(self, iter: I) -> T::Output + pub fn mk_pseudo_rigid_due_to_opaques_from_iter(self, iter: I) -> T::Output where I: Iterator, T: CollectAndApply< (Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>), - PseudoRigidDueToOpaquesBounds<'tcx>, + PseudoRigidDueToOpaques<'tcx>, >, { - T::collect_and_apply(iter, |xs| self.mk_pseudo_rigid_due_to_opaques_bounds(xs)) + T::collect_and_apply(iter, |xs| self.mk_pseudo_rigid_due_to_opaques(xs)) } pub fn mk_clauses_from_iter(self, iter: I) -> T::Output diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 66eb85c91967b..50cfafae93f5f 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -76,13 +76,13 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.mk_predefined_opaques_in_body(data) } - type PseudoRigidDueToOpaquesBounds = solve::PseudoRigidDueToOpaquesBounds<'tcx>; + type PseudoRigidDueToOpaques = solve::PseudoRigidDueToOpaques<'tcx>; - fn mk_pseudo_rigid_due_to_opaques_bounds( + fn mk_pseudo_rigid_due_to_opaques( self, data: &[(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)], - ) -> Self::PseudoRigidDueToOpaquesBounds { - self.mk_pseudo_rigid_due_to_opaques_bounds(data) + ) -> Self::PseudoRigidDueToOpaques { + self.mk_pseudo_rigid_due_to_opaques(data) } type LocalDefIds = &'tcx ty::List; diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 492996a55048b..206f77b47aa6a 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -760,7 +760,7 @@ macro_rules! list_fold { list_fold! { &'tcx ty::List> : mk_poly_existential_predicates, &'tcx ty::List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>: mk_predefined_opaques_in_body, - &'tcx ty::List<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)>: mk_pseudo_rigid_due_to_opaques_bounds, + &'tcx ty::List<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)>: mk_pseudo_rigid_due_to_opaques, &'tcx ty::List> : mk_place_elems, &'tcx ty::List> : mk_patterns, &'tcx ty::List> : mk_outlives, diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 586ddc4c4a861..36861b998e3ca 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -116,7 +116,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { let RawExternalConstraintsData { region_constraints, opaque_types, - pseudo_rigid_due_to_opaques_bounds, + pseudo_rigid_due_to_opaques, normalization_nested_goals, } = external_constraints; let region_constraints = if region_constraints.has_type_flags(NEEDS_CANONICAL) { @@ -135,10 +135,8 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { } else { normalization_nested_goals }; - let pseudo_rigid_due_to_opaques_bounds = canonicalizer - .filter_and_canonicalize_pseudo_rigids_due_to_opaques_bounds( - pseudo_rigid_due_to_opaques_bounds, - ); + let pseudo_rigid_due_to_opaques = canonicalizer + .filter_and_canonicalize_pseudo_rigids_due_to_opaques(pseudo_rigid_due_to_opaques); let value = Response { certainty, @@ -146,9 +144,9 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { external_constraints: delegate.cx().mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types: delegate.cx().mk_predefined_opaques_in_body(&opaque_types), - pseudo_rigid_due_to_opaques_bounds: delegate + pseudo_rigid_due_to_opaques: delegate .cx() - .mk_pseudo_rigid_due_to_opaques_bounds(&pseudo_rigid_due_to_opaques_bounds), + .mk_pseudo_rigid_due_to_opaques(&pseudo_rigid_due_to_opaques), normalization_nested_goals, }), }; @@ -284,17 +282,15 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { predefined_opaques_in_body }; - let pseudo_rigid_due_to_opaques_bounds = rest_canonicalizer - .filter_and_canonicalize_pseudo_rigids_due_to_opaques_bounds( - input.pseudo_rigid_due_to_opaques_bounds.to_vec(), + let pseudo_rigid_due_to_opaques = rest_canonicalizer + .filter_and_canonicalize_pseudo_rigids_due_to_opaques( + input.pseudo_rigid_due_to_opaques.to_vec(), ); - let pseudo_rigid_due_to_opaques_bounds = delegate - .cx() - .mk_pseudo_rigid_due_to_opaques_bounds(&pseudo_rigid_due_to_opaques_bounds); + let pseudo_rigid_due_to_opaques = + delegate.cx().mk_pseudo_rigid_due_to_opaques(&pseudo_rigid_due_to_opaques); - let value = - QueryInput { goal, predefined_opaques_in_body, pseudo_rigid_due_to_opaques_bounds }; + let value = QueryInput { goal, predefined_opaques_in_body, pseudo_rigid_due_to_opaques }; debug_assert!(!value.has_infer(), "unexpected infer in {value:?}"); debug_assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); @@ -487,9 +483,9 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { /// After canonicalizing all the other relevant values, filter out pseudo-rigids that /// sub-unified with no other existing vars and canonicalize the remaining ones. - fn filter_and_canonicalize_pseudo_rigids_due_to_opaques_bounds( + fn filter_and_canonicalize_pseudo_rigids_due_to_opaques( &mut self, - mut pseudo_rigid_due_to_opaques_bounds: Vec<(I::Ty, ty::PseudoRigidDueToOpaquesBound)>, + mut pseudo_rigid_due_to_opaques: Vec<(I::Ty, ty::PseudoRigidDueToOpaquesBound)>, ) -> Vec<(I::Ty, ty::PseudoRigidDueToOpaquesBound)> { let mut res = vec![]; @@ -500,9 +496,9 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { // once in order, we accidentally filter out the first `(?y, ^self: foo)` as `?y` // appears nowhere in preexisting `var_values` when we check it, but it becomes relevant // after we check and canonicalize the second one. - while !pseudo_rigid_due_to_opaques_bounds.is_empty() { + while !pseudo_rigid_due_to_opaques.is_empty() { let prev_len = res.len(); - pseudo_rigid_due_to_opaques_bounds.retain(|entry @ (pseudo_rigid, _)| { + pseudo_rigid_due_to_opaques.retain(|entry @ (pseudo_rigid, _)| { if let ty::Infer(ty::TyVar(vid)) = pseudo_rigid.kind() && self .state diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index 7f95e86e49761..9eac6260d0b20 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -57,7 +57,7 @@ pub(super) fn canonicalize_goal( delegate: &D, goal: Goal, opaque_types: &[(ty::OpaqueTypeKey, I::Ty)], - pseudo_rigid_due_to_opaques_bounds: &[(I::Ty, ty::PseudoRigidDueToOpaquesBound)], + pseudo_rigid_due_to_opaques: &[(I::Ty, ty::PseudoRigidDueToOpaquesBound)], typing_mode: TypingMode, ) -> (ThinVec, I::CanonicalInput) where @@ -69,9 +69,9 @@ where QueryInput { goal, predefined_opaques_in_body: delegate.cx().mk_predefined_opaques_in_body(opaque_types), - pseudo_rigid_due_to_opaques_bounds: delegate + pseudo_rigid_due_to_opaques: delegate .cx() - .mk_pseudo_rigid_due_to_opaques_bounds(pseudo_rigid_due_to_opaques_bounds), + .mk_pseudo_rigid_due_to_opaques(pseudo_rigid_due_to_opaques), }, ); @@ -131,7 +131,7 @@ where let ExternalConstraintsData { region_constraints, opaque_types, - pseudo_rigid_due_to_opaques_bounds, + pseudo_rigid_due_to_opaques, normalization_nested_goals, } = &*external_constraints; @@ -155,7 +155,7 @@ where }; register_new_opaque_types(delegate, opaque_types.as_slice(), span); delegate.register_pseudo_rigid_due_to_opaques_in_storage_with_flattened( - pseudo_rigid_due_to_opaques_bounds.as_slice(), + pseudo_rigid_due_to_opaques.as_slice(), ); (normalization_nested_goals.clone(), certainty) diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index ee66bcd83fcd0..55b34e0090b14 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -1180,8 +1180,8 @@ where let self_ty = goal.predicate.self_ty(); // We only use this hack during HIR typeck. - let pseudo_rigids = match self.typing_mode() { - TypingMode::Typeck { .. } => self.pseudo_rigids_due_to_opaques(self_ty), + let pseudo_rigid = match self.typing_mode() { + TypingMode::Typeck { .. } => self.pseudo_rigid_due_to_opaques(self_ty), TypingMode::Coherence | TypingMode::PostTypeckUntilBorrowck { .. } | TypingMode::PostBorrowck { .. } @@ -1195,14 +1195,13 @@ where } }; - if pseudo_rigids.is_empty() { + if pseudo_rigid.is_empty() { candidates.extend(self.forced_ambiguity(MaybeInfo::AMBIGUOUS)); return Ok(()); } - for (pseudo_rigid, bounds) in &pseudo_rigids { + for bound in &pseudo_rigid { debug!("self ty is sub unified with {pseudo_rigid:?}"); - // We look at all item-bounds of the type being pseudo rigid due to opaques, // instantiating the self type of the bound with the current self // type before considering them as a candidate. Imagine we've got @@ -1210,23 +1209,20 @@ where // type of `impl Trait`, We take the item bound `opaque: Trait` // and replace all occurrences of `opaque` with `?x`. This results // in a `?x: Trait` alias-bound candidate. - for bound in bounds { - candidates.extend(consider_pseudo_rigid_due_to_opaques_bound(self, goal, *bound)); - } + candidates.extend(consider_pseudo_rigid_due_to_opaques_bound(self, goal, *bound)); } // This is rather hacky and unprincipled, but we need this anyway :( // See the comments on // `[ty::PseudoRigidDueToOpaquesBound::opt_unmentioned_projection_bound]` // for details. - if self.typing_mode().should_register_pseudo_rigids_due_to_opaques() - && candidates.is_empty() + if candidates.is_empty() && let Some(ty::NormalizesTo { alias, term }) = G::as_normalizes_to(goal.predicate) && term.as_type().is_some() && let Some(unmentioned) = ty::PseudoRigidDueToOpaquesBound::opt_unmentioned_projection_bound( self.cx(), - pseudo_rigids.into_iter().flat_map(|(_, bounds)| bounds), + pseudo_rigid, ty::ProjectionClause { projection_term: alias, term }, ) { diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 38940adeefc5b..6ca4e2edc1869 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -25,7 +25,7 @@ use thin_vec::ThinVec; use tracing::{Level, debug, instrument, trace, warn}; use super::{ - RawExternalConstraintsData, has_only_region_constraints_or_pseudo_rigid_due_to_opaques_bounds, + RawExternalConstraintsData, has_only_region_constraints_or_pseudo_rigid_due_to_opaques, }; use crate::canonical::{ canonicalize_goal, canonicalize_response, instantiate_and_apply_query_response, @@ -547,7 +547,7 @@ where } delegate.register_pseudo_rigid_due_to_opaques_in_storage_with_flattened( - input.pseudo_rigid_due_to_opaques_bounds.as_slice(), + input.pseudo_rigid_due_to_opaques.as_slice(), ); let initial_opaque_types_storage_num_entries = delegate.opaque_types_storage_num_entries(); @@ -772,14 +772,13 @@ where // so we only canonicalize the lookup table and ignore // duplicate entries. let opaque_types = self.delegate.clone_opaque_types_lookup_table(); - let pseudo_rigid_due_to_opaques_bounds = - self.delegate.clone_pseudo_rigid_due_to_opaques_bounds(); + let pseudo_rigid_due_to_opaques = self.delegate.clone_pseudo_rigid_due_to_opaques(); - let (goal, opaque_types, pseudo_rigid_due_to_opaques_bounds) = + let (goal, opaque_types, pseudo_rigid_due_to_opaques) = self.delegate.deeply_resolve_via_unification_table(( goal, opaque_types, - pseudo_rigid_due_to_opaques_bounds, + pseudo_rigid_due_to_opaques, )); let typing_mode = self.typing_mode(); let step_kind = self.step_kind_for_source(source); @@ -790,7 +789,7 @@ where "{:?} opaques={:?}, pseudo_rigid_due_to_opques_bounds={:?}, goal={:?}", typing_mode, opaque_types, - pseudo_rigid_due_to_opaques_bounds, + pseudo_rigid_due_to_opaques, goal, ) .entered(); @@ -879,7 +878,7 @@ where self.delegate, goal, &opaque_types, - &pseudo_rigid_due_to_opaques_bounds, + &pseudo_rigid_due_to_opaques, typing_mode, ); @@ -907,7 +906,7 @@ where drop(tracing_span); - let before_instantiate_response = self.delegate.num_pseudo_rigid_due_to_opaques_bounds(); + let before_instantiate_response = self.delegate.num_pseudo_rigid_due_to_opaques(); let (normalization_nested_goals, certainty) = instantiate_and_apply_query_response( self.delegate, @@ -916,20 +915,18 @@ where self.origin_span, ); - // `pseudo_rigid_due_to_opaques_bounds` may vary modulo regions which might be able to be unified in + // `pseudo_rigid_due_to_opaques` may vary modulo regions which might be able to be unified in // the caller in the end. So, instead of the response has any, check whether the storage // entries actually changed. // // See `tests/ui/traits/next-solver/opaques/non-defining-use-stall-on-no-actual-change-in-the-caller.rs` - let has_changed = - if !has_only_region_constraints_or_pseudo_rigid_due_to_opaques_bounds(response) - || self.delegate.num_pseudo_rigid_due_to_opaques_bounds() - != before_instantiate_response - { - HasChanged::Yes - } else { - HasChanged::No - }; + let has_changed = if !has_only_region_constraints_or_pseudo_rigid_due_to_opaques(response) + || self.delegate.num_pseudo_rigid_due_to_opaques() != before_instantiate_response + { + HasChanged::Yes + } else { + HasChanged::No + }; // FIXME: We previously had an assert here that checked that recomputing // a goal after applying its constraints did not change its response. @@ -1001,7 +998,7 @@ where let num_opaques_in_storage = canonical_goal.canonical.value.predefined_opaques_in_body.len(); let num_hidden_ty_bounds_in_storage = - canonical_goal.canonical.value.pseudo_rigid_due_to_opaques_bounds.len(); + canonical_goal.canonical.value.pseudo_rigid_due_to_opaques.len(); GoalStalledOn { stalled_vars, @@ -1643,12 +1640,12 @@ where Ok(may_use_unstable_feature(&**self.delegate, param_env, symbol)) } - pub(crate) fn pseudo_rigids_due_to_opaques( + pub(crate) fn pseudo_rigid_due_to_opaques( &self, self_ty: I::Ty, - ) -> Vec<(I::Ty, Vec>)> { + ) -> Vec> { if let ty::Infer(ty::TyVar(vid)) = self_ty.kind() { - self.delegate.pseudo_rigids_due_to_opaques(vid) + self.delegate.pseudo_rigid_due_to_opaques(vid) } else { vec![] } @@ -1764,7 +1761,7 @@ where filter_irrelevant_region_constraints(self.delegate, &var_values, &mut external_constraints); - external_constraints.pseudo_rigid_due_to_opaques_bounds.retain(|(pr, _)| pr.is_ty_var()); + external_constraints.pseudo_rigid_due_to_opaques.retain(|(pr, _)| pr.is_ty_var()); let canonical = canonicalize_response( self.delegate, @@ -1835,17 +1832,17 @@ where // to the `var_values`. let initial_entries = self.initial_opaque_types_storage_num_entries; let opaque_types = self.delegate.clone_opaque_types_added_since(initial_entries); - let pseudo_rigid_due_to_opaques_bounds = - self.delegate.clone_pseudo_rigid_due_to_opaques_bounds_added_since(initial_entries); + let pseudo_rigid_due_to_opaques = + self.delegate.clone_pseudo_rigid_due_to_opaques_added_since(initial_entries); if self.typing_mode().is_erased_not_coherence() { - assert!(opaque_types.is_empty() && pseudo_rigid_due_to_opaques_bounds.is_empty()); + assert!(opaque_types.is_empty() && pseudo_rigid_due_to_opaques.is_empty()); } RawExternalConstraintsData { region_constraints, opaque_types, - pseudo_rigid_due_to_opaques_bounds, + pseudo_rigid_due_to_opaques, normalization_nested_goals, } } @@ -1927,7 +1924,7 @@ fn filter_irrelevant_region_constraints( let RawExternalConstraintsData { region_constraints, opaque_types, - pseudo_rigid_due_to_opaques_bounds, + pseudo_rigid_due_to_opaques, normalization_nested_goals, } = external_constraints; @@ -1944,7 +1941,7 @@ fn filter_irrelevant_region_constraints( // because we skip the RHS of outlives constraints, and `TypeVisitor` doesn't // have a method we can easily override in order to do this. opaque_types.visit_with(&mut vis); - pseudo_rigid_due_to_opaques_bounds.visit_with(&mut vis); + pseudo_rigid_due_to_opaques.visit_with(&mut vis); normalization_nested_goals.visit_with(&mut vis); for (constraint, _) in r.iter() { match constraint { @@ -2100,20 +2097,16 @@ pub(super) fn evaluate_root_goal_for_proof_tree, root_depth: usize, ) -> (Result, NoSolution>, inspect::GoalEvaluation) { let opaque_types = delegate.clone_opaque_types_lookup_table(); - let pseudo_rigid_due_to_opaques_bounds = delegate.clone_pseudo_rigid_due_to_opaques_bounds(); - let (goal, opaque_types, pseudo_rigid_due_to_opaques_bounds) = delegate - .deeply_resolve_via_unification_table(( - goal, - opaque_types, - pseudo_rigid_due_to_opaques_bounds, - )); + let pseudo_rigid_due_to_opaques = delegate.clone_pseudo_rigid_due_to_opaques(); + let (goal, opaque_types, pseudo_rigid_due_to_opaques) = delegate + .deeply_resolve_via_unification_table((goal, opaque_types, pseudo_rigid_due_to_opaques)); let typing_mode = delegate.typing_mode_raw().assert_not_erased(); let (orig_values, canonical_goal) = canonicalize_goal( delegate, goal, &opaque_types, - &pseudo_rigid_due_to_opaques_bounds, + &pseudo_rigid_due_to_opaques, typing_mode.into(), ); diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 0814bdcc59926..9a499d12f1f14 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -61,13 +61,13 @@ fn has_no_inference_or_external_constraints( let ExternalConstraintsData { ref region_constraints, ref opaque_types, - ref pseudo_rigid_due_to_opaques_bounds, + ref pseudo_rigid_due_to_opaques, ref normalization_nested_goals, } = *response.value.external_constraints; response.value.var_values.is_identity() && region_constraints.is_empty() && opaque_types.is_empty() - && pseudo_rigid_due_to_opaques_bounds.is_empty() + && pseudo_rigid_due_to_opaques.is_empty() && normalization_nested_goals.is_empty() } @@ -75,22 +75,22 @@ fn has_only_region_constraints(response: ty::Canonical( +fn has_only_region_constraints_or_pseudo_rigid_due_to_opaques( response: ty::Canonical>, ) -> bool { let ExternalConstraintsData { region_constraints: _, ref opaque_types, - pseudo_rigid_due_to_opaques_bounds: _, + pseudo_rigid_due_to_opaques: _, ref normalization_nested_goals, } = *response.value.external_constraints; response.value.var_values.is_identity_modulo_regions() @@ -465,6 +465,6 @@ pub struct GoalEvaluation { pub struct RawExternalConstraintsData { pub region_constraints: ExternalRegionConstraints, pub opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, - pub pseudo_rigid_due_to_opaques_bounds: Vec<(I::Ty, ty::PseudoRigidDueToOpaquesBound)>, + pub pseudo_rigid_due_to_opaques: Vec<(I::Ty, ty::PseudoRigidDueToOpaquesBound)>, pub normalization_nested_goals: NestedNormalizationGoals, } diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 5cb2110e0550a..1b00877f494df 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -1318,7 +1318,7 @@ where let ExternalConstraintsData { region_constraints: _, ref opaque_types, - ref pseudo_rigid_due_to_opaques_bounds, + ref pseudo_rigid_due_to_opaques, ref normalization_nested_goals, } = *candidate.result.value.external_constraints; debug_assert!(normalization_nested_goals.is_empty()); @@ -1327,7 +1327,7 @@ where // inference state. This is safe after typeck, where hidden types are already // fixed and only regions are inferred, but not during typeck while hidden // types may still contain inference variables. - if !(opaque_types.is_empty() && pseudo_rigid_due_to_opaques_bounds.is_empty()) { + if !(opaque_types.is_empty() && pseudo_rigid_due_to_opaques.is_empty()) { let typing_mode = self.typing_mode(); match typing_mode { diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 98ec65f372954..6ca876daf6c15 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -280,7 +280,7 @@ impl TypingMode { /// item self bounds for pseudo-rigids for that `TypingMode` only. /// /// See also the documentation on [`TypingMode`] about exhaustive matching. - pub fn should_register_pseudo_rigids_due_to_opaques(&self) -> bool { + pub fn should_register_pseudo_rigid_due_to_opaques(&self) -> bool { match self { TypingMode::Typeck { .. } => true, TypingMode::PostTypeckUntilBorrowck { .. } @@ -563,28 +563,25 @@ pub trait InferCtxtLike: Sized { type OpaqueTypeStorageEntries: OpaqueTypeStorageEntries; fn opaque_types_storage_num_entries(&self) -> Self::OpaqueTypeStorageEntries; - fn num_pseudo_rigid_due_to_opaques_bounds(&self) -> usize; + fn num_pseudo_rigid_due_to_opaques(&self) -> usize; fn clone_opaque_types_lookup_table( &self, ) -> Vec<(ty::OpaqueTypeKey, ::Ty)>; - fn clone_pseudo_rigid_due_to_opaques_bounds( + fn clone_pseudo_rigid_due_to_opaques( &self, ) -> Vec<(::Ty, ty::PseudoRigidDueToOpaquesBound)>; fn clone_opaque_types_added_since( &self, prev_entries: Self::OpaqueTypeStorageEntries, ) -> Vec<(ty::OpaqueTypeKey, ::Ty)>; - fn clone_pseudo_rigid_due_to_opaques_bounds_added_since( + fn clone_pseudo_rigid_due_to_opaques_added_since( &self, prev_entries: Self::OpaqueTypeStorageEntries, ) -> Vec<(::Ty, ty::PseudoRigidDueToOpaquesBound)>; - fn pseudo_rigids_due_to_opaques( + fn pseudo_rigid_due_to_opaques( &self, ty_vid: TyVid, - ) -> Vec<( - ::Ty, - Vec>, - )>; + ) -> Vec>; fn register_hidden_type_in_storage( &self, diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 3cc3f39d67516..7d08cfafb4b83 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -129,16 +129,16 @@ pub trait Interner: data: &[(ty::OpaqueTypeKey, Self::Ty)], ) -> Self::PredefinedOpaques; - type PseudoRigidDueToOpaquesBounds: Copy + type PseudoRigidDueToOpaques: Copy + Debug + Hash + Eq + TypeFoldable + SliceLike)>; - fn mk_pseudo_rigid_due_to_opaques_bounds( + fn mk_pseudo_rigid_due_to_opaques( self, data: &[(Self::Ty, ty::PseudoRigidDueToOpaquesBound)], - ) -> Self::PseudoRigidDueToOpaquesBounds; + ) -> Self::PseudoRigidDueToOpaques; type LocalDefIds: Copy + Debug diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index b303dc3009100..109788b4d4d0f 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -456,7 +456,7 @@ pub enum GoalSource { pub struct QueryInput { pub goal: Goal, pub predefined_opaques_in_body: I::PredefinedOpaques, - pub pseudo_rigid_due_to_opaques_bounds: I::PseudoRigidDueToOpaquesBounds, + pub pseudo_rigid_due_to_opaques: I::PseudoRigidDueToOpaques, } impl Eq for QueryInput {} @@ -634,7 +634,7 @@ impl ExternalRegionConstraints { pub struct ExternalConstraintsData { pub region_constraints: ExternalRegionConstraints, pub opaque_types: I::PredefinedOpaques, - pub pseudo_rigid_due_to_opaques_bounds: I::PseudoRigidDueToOpaquesBounds, + pub pseudo_rigid_due_to_opaques: I::PseudoRigidDueToOpaques, pub normalization_nested_goals: NestedNormalizationGoals, } @@ -650,7 +650,7 @@ impl ExternalConstraintsData { Self { region_constraints, opaque_types: cx.mk_predefined_opaques_in_body(&[]), - pseudo_rigid_due_to_opaques_bounds: cx.mk_pseudo_rigid_due_to_opaques_bounds(&[]), + pseudo_rigid_due_to_opaques: cx.mk_pseudo_rigid_due_to_opaques(&[]), normalization_nested_goals: NestedNormalizationGoals::default(), } } @@ -659,12 +659,12 @@ impl ExternalConstraintsData { let ExternalConstraintsData { region_constraints, opaque_types, - pseudo_rigid_due_to_opaques_bounds, + pseudo_rigid_due_to_opaques, normalization_nested_goals, } = self; region_constraints.is_empty() && opaque_types.is_empty() - && pseudo_rigid_due_to_opaques_bounds.is_empty() + && pseudo_rigid_due_to_opaques.is_empty() && normalization_nested_goals.is_empty() } } From 2fe3e9aee5f2b3ec2515fc75c510de9ce9e9e408 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 30 Sep 2026 12:29:43 +0200 Subject: [PATCH 05/12] store pseudo-rigids as `TyVid`s --- compiler/rustc_hir_typeck/src/method/probe.rs | 6 ++- compiler/rustc_infer/src/infer/context.rs | 26 ++++----- compiler/rustc_infer/src/infer/mod.rs | 26 +++------ .../rustc_infer/src/infer/opaque_types/mod.rs | 35 ++---------- .../src/infer/opaque_types/table.rs | 12 ++--- .../src/solve/eval_ctxt/mod.rs | 54 ++++++++++++++----- compiler/rustc_type_ir/src/infer_ctxt.rs | 4 +- 7 files changed, 79 insertions(+), 84 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index c594c46932aec..fb90c4706f44f 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -420,7 +420,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let pseudo_rigid_due_to_opaques = if self.next_trait_solver() { self.tcx.mk_pseudo_rigid_due_to_opaques_from_iter( - self.inner.borrow_mut().opaque_types().iter_pseudo_rigid_due_to_opaques(), + self.inner + .borrow_mut() + .opaque_types() + .iter_pseudo_rigid_due_to_opaques() + .map(|(ty, bound)| (Ty::new_var(self.tcx, ty), bound)), ) } else { ty::List::empty() diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index e3a884266ef6c..368be288abcc6 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::relate::combine::PredicateEmittingRelation; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, Ty, TyCtxt, TyVid, TypeFoldable}; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use rustc_type_ir::solve::TyOrConstInferVar; use rustc_type_ir::{TypeSuperFoldable, TypeVisitableExt}; @@ -81,7 +81,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.overwrite_solver_region_constraint(constraint.with_spans(span)); } - fn universe_of_ty(&self, vid: ty::TyVid) -> Option { + fn universe_of_ty(&self, vid: TyVid) -> Option { match self.try_resolve_ty_var(vid) { Err(universe) => Some(universe), Ok(_) => None, @@ -102,16 +102,16 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { } } - fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid { + fn root_ty_var(&self, var: TyVid) -> TyVid { self.root_var(var) } - fn sub_unification_table_root_var(&self, var: ty::TyVid) -> ty::TyVid { + fn sub_unification_table_root_var(&self, var: TyVid) -> TyVid { self.sub_unification_table_root_var(var) } #[inline] - fn is_sub_unification_table_root_var(&self, vid: ty::TyVid) -> bool { + fn is_sub_unification_table_root_var(&self, vid: TyVid) -> bool { self.inner .borrow() .type_variable_storage @@ -124,7 +124,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.root_const_var(var) } - fn shallow_resolve_ty_var(&self, vid: ty::TyVid) -> Ty<'tcx> { + fn shallow_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> { self.shallow_resolve_ty_var(vid) } @@ -200,11 +200,11 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { }) } - fn equate_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) { + fn equate_ty_vids_raw(&self, a: TyVid, b: TyVid) { self.inner.borrow_mut().type_variables().equate(a, b); } - fn sub_unify_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) { + fn sub_unify_ty_vids_raw(&self, a: TyVid, b: TyVid) { self.sub_unify_ty_vids_raw(a, b); } @@ -220,7 +220,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.inner.borrow_mut().const_unification_table().union(a, b); } - fn instantiate_ty_var_raw(&self, vid: ty::TyVid, ty: Ty<'tcx>) { + fn instantiate_ty_var_raw(&self, vid: TyVid, ty: Ty<'tcx>) { let ty = lower_universe(self, self.try_resolve_ty_var(vid).unwrap_err(), ty); self.inner.borrow_mut().type_variables().instantiate(vid, ty); @@ -239,7 +239,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { &self, relation: &mut R, target_is_expected: bool, - target_vid: ty::TyVid, + target_vid: TyVid, instantiation_variance: ty::Variance, source_ty: Ty<'tcx>, ) -> RelateResult<'tcx, ()> { @@ -351,7 +351,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { } fn clone_pseudo_rigid_due_to_opaques( &self, - ) -> Vec<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)> { + ) -> Vec<(TyVid, ty::PseudoRigidDueToOpaquesBound<'tcx>)> { self.inner.borrow_mut().opaque_types().iter_pseudo_rigid_due_to_opaques().collect() } fn clone_opaque_types_added_since( @@ -368,7 +368,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { fn clone_pseudo_rigid_due_to_opaques_added_since( &self, prev_entries: OpaqueTypeStorageEntries, - ) -> Vec<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)> { + ) -> Vec<(TyVid, ty::PseudoRigidDueToOpaquesBound<'tcx>)> { self.inner .borrow_mut() .opaque_types() @@ -377,7 +377,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { } fn pseudo_rigid_due_to_opaques( &self, - ty_vid: ty::TyVid, + ty_vid: TyVid, ) -> Vec> { self.pseudo_rigid_due_to_opaques(ty_vid) } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index d786d89e3fedb..1fd57ceb9dd8f 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1122,7 +1122,7 @@ impl<'tcx> InferCtxt<'tcx> { &self, ) -> ( Vec<(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)>, - Vec<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)>, + Vec<(TyVid, ty::PseudoRigidDueToOpaquesBound<'tcx>)>, ) { let mut inner = self.inner.borrow_mut(); let (opaques, pseudo_rigids) = inner.opaque_type_storage.take_opaque_types(); @@ -1159,15 +1159,9 @@ impl<'tcx> InferCtxt<'tcx> { let ty_sub_vid = self.sub_unification_table_root_var(ty_vid); let inner = &mut *self.inner.borrow_mut(); let mut type_variables = inner.type_variable_storage.with_log(&mut inner.undo_log); - inner.opaque_type_storage.iter_pseudo_rigid_due_to_opaques().any(|(hidden_ty, _)| { - if let ty::Infer(ty::TyVar(hidden_vid)) = *hidden_ty.kind() { - let opaque_sub_vid = type_variables.sub_unification_table_root_var(hidden_vid); - if opaque_sub_vid == ty_sub_vid { - return true; - } - } - - false + inner.opaque_type_storage.iter_pseudo_rigid_due_to_opaques().any(|(hidden_vid, _)| { + let opaque_sub_vid = type_variables.sub_unification_table_root_var(hidden_vid); + opaque_sub_vid == ty_sub_vid }) } @@ -1225,15 +1219,9 @@ impl<'tcx> InferCtxt<'tcx> { inner .opaque_type_storage .iter_pseudo_rigid_due_to_opaques() - .filter_map(|(pseudo_rigid, bound)| { - if let ty::Infer(ty::TyVar(hidden_vid)) = *pseudo_rigid.kind() { - let opaque_sub_vid = type_variables.sub_unification_table_root_var(hidden_vid); - if opaque_sub_vid == ty_sub_vid { - return Some(bound); - } - } - - None + .filter_map(|(hidden_vid, bound)| { + let opaque_sub_vid = type_variables.sub_unification_table_root_var(hidden_vid); + if opaque_sub_vid == ty_sub_vid { Some(bound) } else { None } }) .collect() } diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index f8c97cbe3c382..5a03e09e93825 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -8,7 +8,6 @@ use rustc_middle::ty::{ TypeVisitableExt, Unnormalized, }; use rustc_span::{Span, bug}; -use smallvec::SmallVec; use tracing::{debug, instrument}; use super::{DefineOpaqueTypes, RegionVariableOrigin}; @@ -214,7 +213,6 @@ impl<'tcx> InferCtxt<'tcx> { bounds: impl IntoIterator>, ) { assert!(self.next_trait_solver()); - let ty::Infer(ty::TyVar(vid)) = *pseudo_rigid.kind() else { return; }; @@ -222,36 +220,13 @@ impl<'tcx> InferCtxt<'tcx> { return; } - let bounds: SmallVec<[_; 8]> = - bounds.into_iter().map(|bound| self.deeply_resolve_ignoring_regions(bound)).collect(); + let bounds: Vec<_> = bounds + .into_iter() + .map(|bound| self.deeply_resolve_via_unification_table(bound)) + .collect(); let ty_sub_vid = self.sub_unification_table_root_var(vid); - let inner = &mut *self.inner.borrow_mut(); - // This is iffy, can't call `type_variables()` as we're already - // borrowing the `opaque_type_storage` here. - let mut type_variables = inner.type_variable_storage.with_log(&mut inner.undo_log); - - // Since we lookup `pseudo_rigids_due_to_opaques` modulo sub-roots, - // it's okay to save them with the preexisting key that - // sub-unified with the given `pseudo_rigid`. - // - // And doing so helps avoiding possibly duplicates (modulo sub roots) - // which is not so good for caching and goal evaluation progress - // heuristics. - let pseudo_rigid = inner - .opaque_type_storage - .iter_pseudo_rigid_due_to_opaques() - .map(|(pr, _)| pr) - .find(|pr| { - if let ty::Infer(ty::TyVar(ty_vid)) = *pr.kind() { - type_variables.sub_unification_table_root_var(ty_vid) == ty_sub_vid - } else { - false - } - }) - .unwrap_or(pseudo_rigid); - - inner.opaque_types().add_pseudo_rigid_due_to_opaques(pseudo_rigid, bounds); + self.inner.borrow_mut().opaque_types().add_pseudo_rigid_due_to_opaques(ty_sub_vid, bounds); } pub fn register_pseudo_rigid_due_to_opaques_in_storage_with_flattened( diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index 62768f1dd0737..ddce76520a75c 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -2,7 +2,7 @@ use std::ops::Deref; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::undo_log::UndoLogs; -use rustc_middle::ty::{self as ty, OpaqueTypeKey, ProvisionalHiddenType, Ty}; +use rustc_middle::ty::{self as ty, OpaqueTypeKey, ProvisionalHiddenType, Ty, TyVid}; use rustc_span::bug; use tracing::instrument; @@ -25,7 +25,7 @@ pub struct OpaqueTypeStorage<'tcx> { /// - When we normalize an associated type whose self-ty is pseudo-rigid, and there does /// not exist a `Projection` clause for that associated type, we register the normalized-to /// term as a new pseudo-rigid. This fixes trait-system-refactor-initiative#248. - pseudo_rigid_due_to_opaques: Vec<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)>, + pseudo_rigid_due_to_opaques: Vec<(TyVid, ty::PseudoRigidDueToOpaquesBound<'tcx>)>, } /// The number of entries in the opaque type storage at a given point. @@ -93,7 +93,7 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { &mut self, ) -> ( impl Iterator, ProvisionalHiddenType<'tcx>)>, - Vec<(Ty<'tcx>, ty::PseudoRigidDueToOpaquesBound<'tcx>)>, + Vec<(TyVid, ty::PseudoRigidDueToOpaquesBound<'tcx>)>, ) { let OpaqueTypeStorage { opaque_types, duplicate_entries, pseudo_rigid_due_to_opaques } = self; @@ -129,7 +129,7 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { pub fn pseudo_rigid_due_to_opaques_added_since( &self, prev_entries: OpaqueTypeStorageEntries, - ) -> impl Iterator, ty::PseudoRigidDueToOpaquesBound<'tcx>)> { + ) -> impl Iterator)> { self.pseudo_rigid_due_to_opaques .iter() .skip(prev_entries.pseudo_rigid_due_to_opaques) @@ -168,7 +168,7 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { pub fn iter_pseudo_rigid_due_to_opaques( &self, - ) -> impl Iterator, ty::PseudoRigidDueToOpaquesBound<'tcx>)> { + ) -> impl Iterator)> { let OpaqueTypeStorage { opaque_types: _, duplicate_entries: _, @@ -226,7 +226,7 @@ impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> { pub fn add_pseudo_rigid_due_to_opaques( &mut self, - pseudo_rigid: Ty<'tcx>, + pseudo_rigid: TyVid, bounds: impl IntoIterator>, ) { let OpaqueTypeStorage { diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 6ca4e2edc1869..70e9ff2096c77 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -772,14 +772,21 @@ where // so we only canonicalize the lookup table and ignore // duplicate entries. let opaque_types = self.delegate.clone_opaque_types_lookup_table(); - let pseudo_rigid_due_to_opaques = self.delegate.clone_pseudo_rigid_due_to_opaques(); - - let (goal, opaque_types, pseudo_rigid_due_to_opaques) = - self.delegate.deeply_resolve_via_unification_table(( - goal, - opaque_types, - pseudo_rigid_due_to_opaques, - )); + let pseudo_rigid_due_to_opaques: Vec<_> = self + .delegate + .clone_pseudo_rigid_due_to_opaques() + .into_iter() + .filter_map(|(vid, bound)| { + let ty = self.delegate.shallow_resolve_ty_var(vid); + if ty.is_ty_var() { + Some((ty, self.delegate.deeply_resolve_via_unification_table(bound))) + } else { + None + } + }) + .collect(); + let (goal, opaque_types) = + self.delegate.deeply_resolve_via_unification_table((goal, opaque_types)); let typing_mode = self.typing_mode(); let step_kind = self.step_kind_for_source(source); @@ -1832,8 +1839,19 @@ where // to the `var_values`. let initial_entries = self.initial_opaque_types_storage_num_entries; let opaque_types = self.delegate.clone_opaque_types_added_since(initial_entries); - let pseudo_rigid_due_to_opaques = - self.delegate.clone_pseudo_rigid_due_to_opaques_added_since(initial_entries); + let pseudo_rigid_due_to_opaques: Vec<_> = self + .delegate + .clone_pseudo_rigid_due_to_opaques_added_since(initial_entries) + .into_iter() + .filter_map(|(vid, bound)| { + let ty = self.delegate.shallow_resolve_ty_var(vid); + if ty.is_ty_var() { + Some((ty, self.delegate.deeply_resolve_via_unification_table(bound))) + } else { + None + } + }) + .collect(); if self.typing_mode().is_erased_not_coherence() { assert!(opaque_types.is_empty() && pseudo_rigid_due_to_opaques.is_empty()); @@ -2097,9 +2115,19 @@ pub(super) fn evaluate_root_goal_for_proof_tree, root_depth: usize, ) -> (Result, NoSolution>, inspect::GoalEvaluation) { let opaque_types = delegate.clone_opaque_types_lookup_table(); - let pseudo_rigid_due_to_opaques = delegate.clone_pseudo_rigid_due_to_opaques(); - let (goal, opaque_types, pseudo_rigid_due_to_opaques) = delegate - .deeply_resolve_via_unification_table((goal, opaque_types, pseudo_rigid_due_to_opaques)); + let pseudo_rigid_due_to_opaques: Vec<_> = delegate + .clone_pseudo_rigid_due_to_opaques() + .into_iter() + .filter_map(|(vid, bound)| { + let ty = delegate.shallow_resolve_ty_var(vid); + if ty.is_ty_var() { + Some((ty, delegate.deeply_resolve_via_unification_table(bound))) + } else { + None + } + }) + .collect(); + let (goal, opaque_types) = delegate.deeply_resolve_via_unification_table((goal, opaque_types)); let typing_mode = delegate.typing_mode_raw().assert_not_erased(); let (orig_values, canonical_goal) = canonicalize_goal( diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 6ca876daf6c15..16d8b640978c5 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -569,7 +569,7 @@ pub trait InferCtxtLike: Sized { ) -> Vec<(ty::OpaqueTypeKey, ::Ty)>; fn clone_pseudo_rigid_due_to_opaques( &self, - ) -> Vec<(::Ty, ty::PseudoRigidDueToOpaquesBound)>; + ) -> Vec<(TyVid, ty::PseudoRigidDueToOpaquesBound)>; fn clone_opaque_types_added_since( &self, prev_entries: Self::OpaqueTypeStorageEntries, @@ -577,7 +577,7 @@ pub trait InferCtxtLike: Sized { fn clone_pseudo_rigid_due_to_opaques_added_since( &self, prev_entries: Self::OpaqueTypeStorageEntries, - ) -> Vec<(::Ty, ty::PseudoRigidDueToOpaquesBound)>; + ) -> Vec<(TyVid, ty::PseudoRigidDueToOpaquesBound)>; fn pseudo_rigid_due_to_opaques( &self, ty_vid: TyVid, From f03ef5cd978acbbe14c72da2817ba52738b0ffca Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 30 Sep 2026 15:26:16 +0200 Subject: [PATCH 06/12] refactor the way we make assoc types pseudo-rigid --- .../src/solve/assembly/mod.rs | 148 +++++++++++------- compiler/rustc_type_ir/src/opaque_ty.rs | 65 +------- ...non-defining-use-projection-on-hidden-1.rs | 12 ++ 3 files changed, 103 insertions(+), 122 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 55b34e0090b14..c658e439be4b2 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -14,7 +14,7 @@ use rustc_type_ir::solve::{ RerunNonErased, RerunReason, RerunResultExt, SizedTraitKind, StalledOnCoroutines, }; use rustc_type_ir::{ - self as ty, AliasTy, Const, Interner, MayBeErased, Region, TypeFlags, TypeFoldable, + self as ty, AliasTerm, AliasTy, Const, Interner, MayBeErased, Region, TypeFlags, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Unnormalized, Upcast, elaborate, }; @@ -1129,55 +1129,7 @@ where assemble_from: AssembleCandidatesFrom, candidates: &mut Vec>, ) -> Result<(), RerunNonErased> { - fn consider_pseudo_rigid_due_to_opaques_bound( - ecx: &mut EvalCtxt<'_, D>, - goal: Goal, - bound: ty::PseudoRigidDueToOpaquesBound, - ) -> Result, NoSolutionOrRerunNonErased> - where - D: SolverDelegate, - I: Interner, - G: GoalKind, - { - let cx = ecx.cx(); - let assumption = bound.instantiate(cx, goal.predicate.self_ty()); - G::probe_and_match_goal_against_assumption( - ecx, - CandidateSource::AliasBound(AliasBoundKind::SelfBounds), - goal, - assumption, - |ecx| { - let cx = ecx.cx(); - // If we are normalzing a projection onto a pseudo-rigid, register it as a new - // pseudo-rigid with its bounds. - // This new pseudo-rigid should be added to storage in this scope, when we actually - // use the bound as a candidate, otherwise it may prevent us from considering blanket impl - // candidate when we should. - // See `tests/ui/impl-trait/non-defining-uses/use-blanket-impl.rs` as an example of such case. - if let Some(ty::NormalizesTo { alias, term }) = - G::as_normalizes_to(goal.predicate) - && let ty::AliasTermKind::ProjectionTy { def_id } = alias.kind - { - ecx.register_pseudo_rigid_due_to_opaques_in_storage( - term.expect_ty(), - ty::PseudoRigidDueToOpaquesBound::iter_item_self_bounds_for_hidden_ty( - cx, - ty::AliasTy::new_from_args( - cx, - ty::AliasTyKind::Projection { def_id }, - alias.args, - ), - ), - ); - } - - // We want to reprove this goal once we've inferred the - // hidden type, so we force the certainty to `Maybe`. - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - }, - ) - } - + let cx = self.cx(); let self_ty = goal.predicate.self_ty(); // We only use this hack during HIR typeck. let pseudo_rigid = match self.typing_mode() { @@ -1202,6 +1154,7 @@ where for bound in &pseudo_rigid { debug!("self ty is sub unified with {pseudo_rigid:?}"); + let assumption = bound.instantiate(cx, goal.predicate.self_ty()); // We look at all item-bounds of the type being pseudo rigid due to opaques, // instantiating the self type of the bound with the current self // type before considering them as a candidate. Imagine we've got @@ -1209,7 +1162,20 @@ where // type of `impl Trait`, We take the item bound `opaque: Trait` // and replace all occurrences of `opaque` with `?x`. This results // in a `?x: Trait` alias-bound candidate. - candidates.extend(consider_pseudo_rigid_due_to_opaques_bound(self, goal, *bound)); + candidates.extend( + G::probe_and_match_goal_against_assumption( + self, + CandidateSource::AliasBound(AliasBoundKind::SelfBounds), + goal, + assumption, + |ecx| { + // We want to reprove this goal once we've inferred the + // hidden type, so we force the certainty to `Maybe`. + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + }, + ) + .map_err_to_rerun()?, + ); } // This is rather hacky and unprincipled, but we need this anyway :( @@ -1218,15 +1184,17 @@ where // for details. if candidates.is_empty() && let Some(ty::NormalizesTo { alias, term }) = G::as_normalizes_to(goal.predicate) - && term.as_type().is_some() - && let Some(unmentioned) = - ty::PseudoRigidDueToOpaquesBound::opt_unmentioned_projection_bound( - self.cx(), - pseudo_rigid, - ty::ProjectionClause { projection_term: alias, term }, - ) + && let Some(unconstrained_ty) = term.as_type() { - candidates.extend(consider_pseudo_rigid_due_to_opaques_bound(self, goal, unmentioned)); + candidates.extend( + self.consider_unconstrained_assoc_type_of_pseudo_rigid_candidate( + goal, + alias, + unconstrained_ty, + &pseudo_rigid, + ) + .map_err_to_rerun()?, + ); } // If the self type is sub unified with any opaque type, we also look at blanket @@ -1234,7 +1202,6 @@ where // // See tests/ui/impl-trait/non-defining-uses/use-blanket-impl.rs for an example. if assemble_from.should_assemble_impl_candidates() { - let cx = self.cx(); let goal_trait_ref = goal.predicate.trait_ref(cx); cx.for_each_blanket_impl(goal.predicate.trait_def_id(cx), |impl_def_id| { @@ -1277,6 +1244,67 @@ where Ok(()) } + /// If the given `alias` is not mentioned among the given `existing_bounds`, + /// create one for it. + /// + /// This is needed to support the non-defining usages like in the following case: + /// + /// ```no_run + /// fn argument_types() -> impl IntoIterator { + /// argument_types().into_iter().collect::>() + /// // ^ ^ + /// // | | + /// // `{opaque}` | + /// // `<{opaque} as IntoIterator>::IntoIter` + /// } + /// ``` + /// + /// We need to solve a projection goal `<{opaque} as IntoIterator>::IntoIter = ?x` to + /// infer the self type for a method call `.collect()`. We can't do so eagerly as + /// it's not specified on the opaque type. We do want to also treat `?x` as + /// pseudo-rigid, so we add an ambiguous candidate which adds all the item bounds + /// of `IntoIterator::IntoIter` as [ty::PseudoRigidDueToOpaquesBound]. + /// + /// This way `?x` is now also a valid self type of a method call. + fn consider_unconstrained_assoc_type_of_pseudo_rigid_candidate>( + &mut self, + goal: Goal, + alias: AliasTerm, + unconstrained_ty: I::Ty, + existing_bounds: &[ty::PseudoRigidDueToOpaquesBound], + ) -> Result, NoSolutionOrRerunNonErased> { + let cx = self.cx(); + let trait_def_id = alias.trait_def_id(cx); + // We only treat associated types as pseudo-rigid if their self type is pseudo-rigid and required + // to implement the relevant trait. + if !existing_bounds.iter().any(|bound| bound.is_trait_clause_with_def_id(trait_def_id)) { + return Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution)); + } + + let trivial_assumption = + ty::ProjectionClause { projection_term: alias.into(), term: unconstrained_ty.into() } + .upcast(cx); + G::probe_and_match_goal_against_assumption( + self, + CandidateSource::AliasBound(AliasBoundKind::SelfBounds), + goal, + trivial_assumption, + |ecx| { + ecx.register_pseudo_rigid_due_to_opaques_in_storage( + unconstrained_ty, + ty::PseudoRigidDueToOpaquesBound::iter_item_self_bounds_for_hidden_ty( + cx, + alias.expect_ty(), + ), + ); + + // We want to reprove this goal once we've inferred the + // hidden type, so we force the certainty to `Maybe`. + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + }, + ) + } + /// Assemble and merge candidates for goals which are related to an underlying trait /// goal. Right now, this is normalizes-to and host effect goals. /// diff --git a/compiler/rustc_type_ir/src/opaque_ty.rs b/compiler/rustc_type_ir/src/opaque_ty.rs index 7f89d99f0cae2..2793e6655ed13 100644 --- a/compiler/rustc_type_ir/src/opaque_ty.rs +++ b/compiler/rustc_type_ir/src/opaque_ty.rs @@ -7,7 +7,7 @@ use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisit use crate::inherent::*; use crate::{ self as ty, Binder, Interner, Region, TypeFoldable, TypeFolder, TypeSuperFoldable, - TypeVisitableExt, Upcast, + TypeVisitableExt, }; #[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] @@ -98,67 +98,8 @@ impl PseudoRigidDueToOpaquesBound { }) } - /// If the given `projection` is not mentioned among the given `existing_bounds`, - /// create one for it. - /// - /// This is needed to support the non-defining usages like in the following case: - /// - /// ```no_run - /// fn argument_types() -> impl IntoIterator { - /// argument_types().into_iter().collect::>() - /// // ^ ^ - /// // | | - /// // `{opaque}` | - /// // `<{opaque} as IntoIterator>::IntoIter` - /// } - /// ``` - /// - /// We need to solve a projection goal `<{opaque} as IntoIterator>::IntoIter = ?x` to - /// infer the self type for a method call `collect()`. But as the given bounds in the - /// scope don't mention the assoc type `IntoIterator::IntoIter` at all, we just get an - /// ambiguous response with unconstrained infer var, from no candidate. This is rejected - /// for being a self type for a method call because we allow self type being an infer - /// var if and only if it's considered as a pseudo-rigid due to opaques, i.e. we have - /// a bound for it in opaque ty storage. - /// So we conjure up one via its method and register it to the sol - pub fn opt_unmentioned_projection_bound( - cx: I, - existing_bounds: impl IntoIterator, - proj: ty::ProjectionClause, - ) -> Option { - let trait_def_id = proj.trait_def_id(cx); - let mut mentions_trait = false; - for bound in existing_bounds.into_iter() { - if bound - .bound - .skip_binder() - .as_projection_clause() - .is_some_and(|b| b.item_def_id() == proj.def_id()) - { - // Mentioned already - return None; - } - - if bound - .bound - .skip_binder() - .as_trait_clause() - .is_some_and(|b| b.def_id() == trait_def_id) - { - mentions_trait = true; - } - } - - if !mentions_trait { - return None; - } - - let bound: I::Clause = proj.upcast(cx); - let bound = Binder::bind_with_vars( - bound.fold_with(&mut ReplaceSelfTyWithAnonBound::new(cx, proj.self_ty())), - I::BoundVarKinds::from_vars(cx, [ty::BoundVariableKind::Ty(ty::BoundTyKind::Anon)]), - ); - Some(PseudoRigidDueToOpaquesBound { bound }) + pub fn is_trait_clause_with_def_id(&self, def_id: I::TraitId) -> bool { + self.bound.skip_binder().as_trait_clause().is_some_and(|b| b.def_id() == def_id) } pub fn instantiate(self, cx: I, self_ty: I::Ty) -> I::Clause { diff --git a/tests/ui/traits/next-solver/opaques/non-defining-use-projection-on-hidden-1.rs b/tests/ui/traits/next-solver/opaques/non-defining-use-projection-on-hidden-1.rs index 18208b18f2abd..1a2438e2f8f95 100644 --- a/tests/ui/traits/next-solver/opaques/non-defining-use-projection-on-hidden-1.rs +++ b/tests/ui/traits/next-solver/opaques/non-defining-use-projection-on-hidden-1.rs @@ -24,4 +24,16 @@ fn argument_types() -> impl IntoIterator { argument_types().into_iter().collect::>() } +// Check that we eagerly normalize `<::IntoIter as Iterator>::Item` +// to `&'static str`. +fn item_bound_norm_to_assoc() -> impl IntoIterator { + fn get_assoc(x: T) -> ::Item { todo!() } + if false { + get_assoc(item_bound_norm_to_assoc()).len(); + } + + std::iter::once("") +} + + fn main() {} From 2df1c7cf3c7598a0c01b5cf0f37a4f482c108b9c Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 30 Sep 2026 15:41:54 +0200 Subject: [PATCH 07/12] improve rerun condition --- compiler/rustc_infer/src/infer/context.rs | 3 + .../src/solve/assembly/mod.rs | 3 +- .../src/solve/eval_ctxt/fast_path.rs | 6 ++ .../src/solve/eval_ctxt/mod.rs | 29 ++++--- compiler/rustc_type_ir/src/infer_ctxt.rs | 1 + compiler/rustc_type_ir/src/solve/mod.rs | 79 ++++++++----------- ...paque-or-has-infer-as-hidden-in-codegen.rs | 4 +- 7 files changed, 61 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 368be288abcc6..cc6ee6b6c1428 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -375,6 +375,9 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { .pseudo_rigid_due_to_opaques_added_since(prev_entries) .collect() } + fn is_pseudo_rigid_due_to_opaques(&self, ty_vid: TyVid) -> bool { + self.is_pseudo_rigid_due_to_opaques(ty_vid) + } fn pseudo_rigid_due_to_opaques( &self, ty_vid: TyVid, diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index c658e439be4b2..062bd100b4090 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -1141,8 +1141,7 @@ where | TypingMode::Reflection | TypingMode::Codegen => vec![], TypingMode::ErasedNotCoherence(MayBeErased) => { - self.opaque_accesses - .rerun_if_any_opaque_has_infer_as_hidden_type(RerunReason::SelfTyInfer)?; + self.opaque_accesses.rerun_if_any_pseudo_rigid(RerunReason::SelfTyInfer)?; Vec::new() } }; diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/fast_path.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/fast_path.rs index 26941e3a255cd..851b2b3005094 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/fast_path.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/fast_path.rs @@ -99,6 +99,12 @@ where accessed_opaques, delegate.typing_mode_raw(), &delegate.clone_opaque_types_lookup_table(), + || { + delegate.num_pseudo_rigid_due_to_opaques() != 0 + && sub_roots + .iter() + .any(|&vid| delegate.is_pseudo_rigid_due_to_opaques(vid)) + }, ) { RerunDecision::Yes => {} RerunDecision::EagerlyPropagateToParent => { diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 70e9ff2096c77..f1ca40f712e40 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -856,6 +856,7 @@ where accessed_opaques, self.typing_mode(), &opaque_types, + || !pseudo_rigid_due_to_opaques.is_empty(), ); match should_rerun { RerunDecision::Yes => debug!("rerunning in original typing mode"), @@ -1994,11 +1995,12 @@ enum RerunDecision { EagerlyPropagateToParent, } -#[tracing::instrument(ret)] +#[tracing::instrument(level = "debug", skip(parent_has_pseudo_rigid_in_storage), ret)] fn should_rerun_after_erased_canonicalization( AccessedOpaques { reason: _, rerun }: AccessedOpaques, original_typing_mode: TypingMode, parent_opaque_types: &[(OpaqueTypeKey, I::Ty)], + parent_has_pseudo_rigid_in_storage: impl FnOnce() -> bool, ) -> RerunDecision { let parent_opaque_def_ids = parent_opaque_types.iter().map(|(key, _)| key.def_id.into()); let opaque_in_storage = |opaques: I::LocalDefIds, def_ids: SmallCopySet<_>| { @@ -2014,13 +2016,6 @@ fn should_rerun_after_erased_canonicalization( RerunDecision::No } }; - let any_opaque_has_infer_as_hidden = || { - if parent_opaque_types.iter().any(|(_, ty)| ty.is_ty_var()) { - RerunDecision::Yes - } else { - RerunDecision::No - } - }; match (rerun, original_typing_mode) { // ============================= @@ -2045,11 +2040,15 @@ fn should_rerun_after_erased_canonicalization( | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: opaques }, ) => opaque_in_storage(opaques, defids), // ============================= - (RerunCondition::AnyOpaqueHasInferAsHidden, TypingMode::Typeck { .. }) => { - any_opaque_has_infer_as_hidden() + (RerunCondition::PseudoRigidInStorage, TypingMode::Typeck { .. }) => { + if parent_has_pseudo_rigid_in_storage() { + RerunDecision::Yes + } else { + RerunDecision::No + } } ( - RerunCondition::AnyOpaqueHasInferAsHidden, + RerunCondition::PseudoRigidInStorage, TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis | TypingMode::Codegen @@ -2058,14 +2057,14 @@ fn should_rerun_after_erased_canonicalization( ) => RerunDecision::No, // ============================= ( - RerunCondition::OpaqueInStorageOrAnyOpaqueHasInferAsHidden(_), + RerunCondition::OpaqueInStorageOrPseudoRigidInStorage(_), TypingMode::PostAnalysis | TypingMode::Codegen | TypingMode::Reflection, ) => RerunDecision::Yes, ( - RerunCondition::OpaqueInStorageOrAnyOpaqueHasInferAsHidden(defids), + RerunCondition::OpaqueInStorageOrPseudoRigidInStorage(defids), TypingMode::Typeck { defining_opaque_types_and_generators: opaques }, ) => { - if let RerunDecision::Yes = any_opaque_has_infer_as_hidden() { + if parent_has_pseudo_rigid_in_storage() { RerunDecision::Yes } else if let RerunDecision::Yes = opaque_in_storage(opaques, defids) { RerunDecision::Yes @@ -2074,7 +2073,7 @@ fn should_rerun_after_erased_canonicalization( } } ( - RerunCondition::OpaqueInStorageOrAnyOpaqueHasInferAsHidden(defids), + RerunCondition::OpaqueInStorageOrPseudoRigidInStorage(defids), TypingMode::PostBorrowck { defined_opaque_types: opaques } | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: opaques }, ) => opaque_in_storage(opaques, defids), diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 16d8b640978c5..c87105e9bfd02 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -578,6 +578,7 @@ pub trait InferCtxtLike: Sized { &self, prev_entries: Self::OpaqueTypeStorageEntries, ) -> Vec<(TyVid, ty::PseudoRigidDueToOpaquesBound)>; + fn is_pseudo_rigid_due_to_opaques(&self, ty_vid: TyVid) -> bool; fn pseudo_rigid_due_to_opaques( &self, ty_vid: TyVid, diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 109788b4d4d0f..dabf118718d8d 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -165,12 +165,12 @@ impl AsRef<[T]> for SmallCopySet { /// Information about how we accessed opaque types /// This is what the trait solver does when each states is encountered: /// -/// | | bail? | rerun goal? | -/// | ----------------------- | ----- | -------------------------------------------------------------------------------------------------------------------- | -/// | never | no | no | -/// | always | yes | yes | -/// | [defid in storage] | no | only if any of the defids in the list is in the opaque type storage OR if TypingMode::PostAnalysis | -/// | opaque with hidden type | no | only if any of the opaques in the opaque type storage has a hidden type in this list AND if TypingMode::Typeck | +/// | | bail? | rerun goal? | +/// | ------------------------- | ----- | -------------------------------------------------------------------------------------------------------------------- | +/// | never | no | no | +/// | always | yes | yes | +/// | [defid in storage] | no | only if any of the defids in the list is in the opaque type storage OR if TypingMode::PostAnalysis | +/// | [pseudo-rigid in storage] | no | only if there's a pseudo-rigid relevant for this goal | /// /// - "bail" is implemented with [`should_bail`](Self::should_bail). /// If true, we're abandoning our attempt to canonicalize in [`TypingMode::ErasedNotCoherence`], @@ -187,14 +187,14 @@ pub enum RerunCondition { Never, /// Note that this only reruns according to the condition *if* we are in [`TypingMode::Typeck`]. - AnyOpaqueHasInferAsHidden, + PseudoRigidInStorage, /// Note: unconditionally reruns in postanalysis OpaqueInStorage(SmallCopySet), - /// Merges [`Self::AnyOpaqueHasInferAsHidden`] and [`Self::OpaqueInStorage`]. + /// Merges [`Self::PseudoRigidInStorage`] and [`Self::OpaqueInStorage`]. /// Note that just like the unmerged [`Self::OpaqueInStorage`], that part of the /// condition only matters in [`TypingMode::Typeck`] - OpaqueInStorageOrAnyOpaqueHasInferAsHidden(SmallCopySet), + OpaqueInStorageOrPseudoRigidInStorage(SmallCopySet), Always, } @@ -224,35 +224,27 @@ impl RerunCondition { (Self::OpaqueInStorage(a), Self::OpaqueInStorage(b)) => { a.union(b).map(Self::OpaqueInStorage).unwrap_or(Self::Always) } - (Self::AnyOpaqueHasInferAsHidden, Self::AnyOpaqueHasInferAsHidden) => { - Self::AnyOpaqueHasInferAsHidden + (Self::PseudoRigidInStorage, Self::PseudoRigidInStorage) => Self::PseudoRigidInStorage, + (Self::PseudoRigidInStorage, Self::OpaqueInStorageOrPseudoRigidInStorage(a)) + | (Self::OpaqueInStorageOrPseudoRigidInStorage(a), Self::PseudoRigidInStorage) => { + Self::OpaqueInStorage(a) } - ( - Self::AnyOpaqueHasInferAsHidden, - Self::OpaqueInStorageOrAnyOpaqueHasInferAsHidden(a), - ) - | ( - Self::OpaqueInStorageOrAnyOpaqueHasInferAsHidden(a), - Self::AnyOpaqueHasInferAsHidden, - ) => Self::OpaqueInStorage(a), ( - Self::OpaqueInStorageOrAnyOpaqueHasInferAsHidden(a), - Self::OpaqueInStorageOrAnyOpaqueHasInferAsHidden(b), - ) => a - .union(b) - .map(Self::OpaqueInStorageOrAnyOpaqueHasInferAsHidden) - .unwrap_or(Self::Always), - - (Self::OpaqueInStorage(a), Self::OpaqueInStorageOrAnyOpaqueHasInferAsHidden(b)) - | (Self::OpaqueInStorageOrAnyOpaqueHasInferAsHidden(b), Self::OpaqueInStorage(a)) => a - .union(b) - .map(Self::OpaqueInStorageOrAnyOpaqueHasInferAsHidden) - .unwrap_or(Self::Always), - - (Self::OpaqueInStorage(a), Self::AnyOpaqueHasInferAsHidden) - | (Self::AnyOpaqueHasInferAsHidden, Self::OpaqueInStorage(a)) => { - Self::OpaqueInStorageOrAnyOpaqueHasInferAsHidden(a) + Self::OpaqueInStorageOrPseudoRigidInStorage(a), + Self::OpaqueInStorageOrPseudoRigidInStorage(b), + ) => { + a.union(b).map(Self::OpaqueInStorageOrPseudoRigidInStorage).unwrap_or(Self::Always) + } + + (Self::OpaqueInStorage(a), Self::OpaqueInStorageOrPseudoRigidInStorage(b)) + | (Self::OpaqueInStorageOrPseudoRigidInStorage(b), Self::OpaqueInStorage(a)) => { + a.union(b).map(Self::OpaqueInStorageOrPseudoRigidInStorage).unwrap_or(Self::Always) + } + + (Self::OpaqueInStorage(a), Self::PseudoRigidInStorage) + | (Self::PseudoRigidInStorage, Self::OpaqueInStorage(a)) => { + Self::OpaqueInStorageOrPseudoRigidInStorage(a) } }; debug!("merging rerun state {self:?} + {other:?} => {merged:?}"); @@ -265,8 +257,8 @@ impl RerunCondition { Self::Always => Err(RerunNonErased(())), Self::Never | Self::OpaqueInStorage(_) - | Self::OpaqueInStorageOrAnyOpaqueHasInferAsHidden(_) - | Self::AnyOpaqueHasInferAsHidden => Ok(()), + | Self::OpaqueInStorageOrPseudoRigidInStorage(_) + | Self::PseudoRigidInStorage => Ok(()), } } @@ -277,9 +269,9 @@ impl RerunCondition { match self { Self::Never => false, Self::Always - | Self::OpaqueInStorageOrAnyOpaqueHasInferAsHidden(_) + | Self::OpaqueInStorageOrPseudoRigidInStorage(_) | Self::OpaqueInStorage(_) - | Self::AnyOpaqueHasInferAsHidden => true, + | Self::PseudoRigidInStorage => true, } } } @@ -367,14 +359,11 @@ impl AccessedOpaques { }) } - pub fn rerun_if_any_opaque_has_infer_as_hidden_type( - &mut self, - reason: RerunReason, - ) -> Result<(), RerunNonErased> { - debug!("set rerun if any opaque in the storage has a hidden type that is an infer var"); + pub fn rerun_if_any_pseudo_rigid(&mut self, reason: RerunReason) -> Result<(), RerunNonErased> { + debug!("set rerun if any inference variable is pseudo-rigid"); self.update(AccessedOpaques { reason: Some(reason), - rerun: RerunCondition::AnyOpaqueHasInferAsHidden, + rerun: RerunCondition::PseudoRigidInStorage, }) } } diff --git a/tests/ui/traits/next-solver/rerun-if-any-opaque-or-has-infer-as-hidden-in-codegen.rs b/tests/ui/traits/next-solver/rerun-if-any-opaque-or-has-infer-as-hidden-in-codegen.rs index 8f691ad8f4c45..ea14aea9a6258 100644 --- a/tests/ui/traits/next-solver/rerun-if-any-opaque-or-has-infer-as-hidden-in-codegen.rs +++ b/tests/ui/traits/next-solver/rerun-if-any-opaque-or-has-infer-as-hidden-in-codegen.rs @@ -15,7 +15,7 @@ fn main() { // The blanket impl requires `FlatMap<...>: Iterator`. // The `Iterator` impl of `FlatMap` has nested goals: // `Projection(Fn::Output, iter::Once`. - // We normalize this goal and set rerun condition to `AnyOpaqueHasInferAsHidden` + // We normalize this goal and set rerun condition to `PseudoRigidInStorage` // with reason `SelfTyInfer` because we instantiated impls with infers when // assembling candidates for intermediate goals. // Then we evaluate the normalized goal: @@ -25,7 +25,7 @@ fn main() { // But the expected term is revealed `iter::Once` thus relating failed. // The goal fails with rerun condition `OpaqueInStorage(parse_feature::opaque)`. // This goal should be rerun in `TypingMode::Codegen` mode, but - // `AnyOpaqueHasInferAsHidden + OpaqueInStorage = OpaqueInStorageOrAnyOpaqueHasInferAsHidden` + // `PseudoRigidInStorage + OpaqueInStorage = OpaqueInStorageOrPseudoRigidInStorage` // which didn't trigger rerun in `TypingMode::Codegen` mode previously. mk_vec() .into_iter() From 19163b9d21954166d355bd03990903cd37daaf78 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 30 Sep 2026 15:48:16 +0200 Subject: [PATCH 08/12] small cleanup --- .../src/canonical/canonicalizer.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 36861b998e3ca..cf8d7eb551a38 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -144,9 +144,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { external_constraints: delegate.cx().mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types: delegate.cx().mk_predefined_opaques_in_body(&opaque_types), - pseudo_rigid_due_to_opaques: delegate - .cx() - .mk_pseudo_rigid_due_to_opaques(&pseudo_rigid_due_to_opaques), + pseudo_rigid_due_to_opaques, normalization_nested_goals, }), }; @@ -287,9 +285,6 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { input.pseudo_rigid_due_to_opaques.to_vec(), ); - let pseudo_rigid_due_to_opaques = - delegate.cx().mk_pseudo_rigid_due_to_opaques(&pseudo_rigid_due_to_opaques); - let value = QueryInput { goal, predefined_opaques_in_body, pseudo_rigid_due_to_opaques }; debug_assert!(!value.has_infer(), "unexpected infer in {value:?}"); @@ -486,7 +481,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { fn filter_and_canonicalize_pseudo_rigids_due_to_opaques( &mut self, mut pseudo_rigid_due_to_opaques: Vec<(I::Ty, ty::PseudoRigidDueToOpaquesBound)>, - ) -> Vec<(I::Ty, ty::PseudoRigidDueToOpaquesBound)> { + ) -> I::PseudoRigidDueToOpaques { let mut res = vec![]; // This should be done in fixed-point iteration, because we may have some pseudo-rigid @@ -498,14 +493,14 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { // after we check and canonicalize the second one. while !pseudo_rigid_due_to_opaques.is_empty() { let prev_len = res.len(); - pseudo_rigid_due_to_opaques.retain(|entry @ (pseudo_rigid, _)| { - if let ty::Infer(ty::TyVar(vid)) = pseudo_rigid.kind() + pseudo_rigid_due_to_opaques.retain(|&(ty, bound)| { + if let ty::Infer(ty::TyVar(vid)) = ty.kind() && self .state .sub_root_lookup_table .contains_key(&self.delegate.sub_unification_table_root_var(vid)) { - res.push((*entry).fold_with(self)); + res.push(((ty, bound)).fold_with(self)); false } else { true @@ -516,7 +511,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { } } - res + self.delegate.cx().mk_pseudo_rigid_due_to_opaques(&res) } } From 1751932c83c3e32ed433c68f5cb4fd437970a5f9 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 30 Sep 2026 15:56:11 +0200 Subject: [PATCH 09/12] avoid some unnecessary interning --- .../src/canonical/canonicalizer.rs | 17 ++++++++--------- .../src/canonical/mod.rs | 17 ++++++----------- .../src/solve/eval_ctxt/mod.rs | 12 ++++++------ 3 files changed, 20 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index cf8d7eb551a38..81c064ae84d16 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -261,34 +261,33 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { /// variable in the future by changing the way we detect global where-bounds. pub(super) fn canonicalize_input>( delegate: &'a D, - input: QueryInput, + Goal { param_env, predicate }: Goal, + predefined_opaques_in_body: Vec<(ty::OpaqueTypeKey, I::Ty)>, + pseudo_rigid_due_to_opaques: Vec<(I::Ty, ty::PseudoRigidDueToOpaquesBound)>, ) -> (ThinVec, ty::Canonical>) { // First canonicalize the `param_env` while keeping `'static`. This produces a // canonicalizer that can canonicalize the rest of the input without keeping `'static`. - let (param_env, mut rest_canonicalizer) = - Self::canonicalize_param_env(delegate, input.goal.param_env); + let (param_env, mut rest_canonicalizer) = Self::canonicalize_param_env(delegate, param_env); - let predicate = input.goal.predicate; let predicate = predicate.fold_with(&mut rest_canonicalizer); let goal = Goal { param_env, predicate }; - let predefined_opaques_in_body = input.predefined_opaques_in_body; let predefined_opaques_in_body = if predefined_opaques_in_body.has_type_flags(NEEDS_CANONICAL) { predefined_opaques_in_body.fold_with(&mut rest_canonicalizer) } else { predefined_opaques_in_body }; + let predefined_opaques_in_body = + delegate.cx().mk_predefined_opaques_in_body(&predefined_opaques_in_body); let pseudo_rigid_due_to_opaques = rest_canonicalizer - .filter_and_canonicalize_pseudo_rigids_due_to_opaques( - input.pseudo_rigid_due_to_opaques.to_vec(), - ); + .filter_and_canonicalize_pseudo_rigids_due_to_opaques(pseudo_rigid_due_to_opaques); let value = QueryInput { goal, predefined_opaques_in_body, pseudo_rigid_due_to_opaques }; - debug_assert!(!value.has_infer(), "unexpected infer in {value:?}"); debug_assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); + let (max_universe, variables, var_kinds) = rest_canonicalizer.finalize(); (variables, Canonical { max_universe, var_kinds, value }) } diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index 9eac6260d0b20..a9ef3b1600cfa 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -27,8 +27,7 @@ use tracing::instrument; use crate::delegate::SolverDelegate; use crate::solve::{ CanonicalResponse, Certainty, ExternalConstraintsData, ExternalRegionConstraints, Goal, - NestedNormalizationGoals, QueryInput, RawExternalConstraintsData, Response, - VisibleForLeakCheck, inspect, + NestedNormalizationGoals, RawExternalConstraintsData, Response, VisibleForLeakCheck, inspect, }; pub mod canonicalizer; @@ -56,8 +55,8 @@ impl ResponseT for inspect::State { pub(super) fn canonicalize_goal( delegate: &D, goal: Goal, - opaque_types: &[(ty::OpaqueTypeKey, I::Ty)], - pseudo_rigid_due_to_opaques: &[(I::Ty, ty::PseudoRigidDueToOpaquesBound)], + opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, + pseudo_rigid_due_to_opaques: Vec<(I::Ty, ty::PseudoRigidDueToOpaquesBound)>, typing_mode: TypingMode, ) -> (ThinVec, I::CanonicalInput) where @@ -66,13 +65,9 @@ where { let (orig_values, canonical) = Canonicalizer::canonicalize_input( delegate, - QueryInput { - goal, - predefined_opaques_in_body: delegate.cx().mk_predefined_opaques_in_body(opaque_types), - pseudo_rigid_due_to_opaques: delegate - .cx() - .mk_pseudo_rigid_due_to_opaques(pseudo_rigid_due_to_opaques), - }, + goal, + opaque_types, + pseudo_rigid_due_to_opaques, ); let query_input = delegate.cx().mk_canonical_input(ty::CanonicalQueryInput { diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index f1ca40f712e40..613a4646f35d6 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -844,8 +844,8 @@ where let (orig_values, canonical_goal) = canonicalize_goal( self.delegate, goal, - &[], - &[], + Vec::new(), + Vec::new(), TypingMode::ErasedNotCoherence(MayBeErased), ); @@ -885,8 +885,8 @@ where let (orig_values, canonical_goal) = canonicalize_goal( self.delegate, goal, - &opaque_types, - &pseudo_rigid_due_to_opaques, + opaque_types, + pseudo_rigid_due_to_opaques, typing_mode, ); @@ -2132,8 +2132,8 @@ pub(super) fn evaluate_root_goal_for_proof_tree, let (orig_values, canonical_goal) = canonicalize_goal( delegate, goal, - &opaque_types, - &pseudo_rigid_due_to_opaques, + opaque_types, + pseudo_rigid_due_to_opaques, typing_mode.into(), ); From 76c2bd3ef47abc7bcc84baa55695dad3e2a65839 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 30 Sep 2026 16:09:26 +0200 Subject: [PATCH 10/12] dedup fast path --- .../src/canonical/canonicalizer.rs | 48 ++++++------------- .../src/canonical/mod.rs | 2 +- 2 files changed, 16 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 81c064ae84d16..f4edcd33a6027 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -2,6 +2,7 @@ use std::collections::hash_map::Entry; use std::mem; use rustc_type_ir::inherent::*; +use rustc_type_ir::solve::inspect::State; use rustc_type_ir::solve::{Certainty, ExternalConstraintsData, Goal, QueryInput, Response}; use rustc_type_ir::{ self as ty, Canonical, CanonicalParamEnvCacheEntry, CanonicalVarKind, CanonicalVarValues, @@ -78,18 +79,14 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { Canonicalizer { delegate, canonicalize_mode, state: delegate.obtain_canonicalizer_state() } } - pub(super) fn canonicalize_response>( + pub(super) fn canonicalize_inspect_state>( delegate: &'a D, max_input_universe: ty::UniverseIndex, - value: T, - ) -> ty::Canonical { + value: State, + ) -> ty::Canonical> { let mut canonicalizer = Canonicalizer::new(delegate, CanonicalizeMode::Response { max_input_universe }); - let value = if value.has_type_flags(NEEDS_CANONICAL) { - value.fold_with(&mut canonicalizer) - } else { - value - }; + let value = canonicalizer.canonicalize_value(value); debug_assert!(!value.has_infer(), "unexpected infer in {value:?}"); debug_assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); let (max_universe, _variables, var_kinds) = canonicalizer.finalize(); @@ -107,11 +104,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { let mut canonicalizer = Canonicalizer::new(delegate, CanonicalizeMode::Response { max_input_universe }); - let var_values = if var_values.has_type_flags(NEEDS_CANONICAL) { - var_values.fold_with(&mut canonicalizer) - } else { - var_values - }; + let var_values = canonicalizer.canonicalize_value(var_values); let RawExternalConstraintsData { region_constraints, @@ -119,22 +112,11 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { pseudo_rigid_due_to_opaques, normalization_nested_goals, } = external_constraints; - let region_constraints = if region_constraints.has_type_flags(NEEDS_CANONICAL) { - region_constraints.fold_with(&mut canonicalizer) - } else { - region_constraints - }; - let opaque_types = if opaque_types.has_type_flags(NEEDS_CANONICAL) { - opaque_types.fold_with(&mut canonicalizer) - } else { - opaque_types - }; + let region_constraints = canonicalizer.canonicalize_value(region_constraints); + let opaque_types = canonicalizer.canonicalize_value(opaque_types); let normalization_nested_goals = - if normalization_nested_goals.has_type_flags(NEEDS_CANONICAL) { - normalization_nested_goals.fold_with(&mut canonicalizer) - } else { - normalization_nested_goals - }; + canonicalizer.canonicalize_value(normalization_nested_goals); + let pseudo_rigid_due_to_opaques = canonicalizer .filter_and_canonicalize_pseudo_rigids_due_to_opaques(pseudo_rigid_due_to_opaques); @@ -273,11 +255,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { let goal = Goal { param_env, predicate }; let predefined_opaques_in_body = - if predefined_opaques_in_body.has_type_flags(NEEDS_CANONICAL) { - predefined_opaques_in_body.fold_with(&mut rest_canonicalizer) - } else { - predefined_opaques_in_body - }; + rest_canonicalizer.canonicalize_value(predefined_opaques_in_body); let predefined_opaques_in_body = delegate.cx().mk_predefined_opaques_in_body(&predefined_opaques_in_body); @@ -292,6 +270,10 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { (variables, Canonical { max_universe, var_kinds, value }) } + fn canonicalize_value>(&mut self, value: T) -> T { + if value.has_type_flags(NEEDS_CANONICAL) { value.fold_with(self) } else { value } + } + fn get_or_insert_bound_var( &mut self, arg: impl Into, diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index a9ef3b1600cfa..70ff2889bc79d 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -581,7 +581,7 @@ where let var_values = CanonicalVarValues { var_values: delegate.cx().mk_args(var_values) }; let state = inspect::State { var_values, data }; let state = delegate.deeply_resolve_via_unification_table(state); - Canonicalizer::canonicalize_response(delegate, max_input_universe, state) + Canonicalizer::canonicalize_inspect_state(delegate, max_input_universe, state) } // FIXME: needs to be pub to be accessed by downstream From 025b73bacb9a25cfb85668738dfc3d742cb576e2 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 30 Sep 2026 16:12:38 +0200 Subject: [PATCH 11/12] improve comment --- compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 062bd100b4090..4bdac3dccf056 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -1177,10 +1177,7 @@ where ); } - // This is rather hacky and unprincipled, but we need this anyway :( - // See the comments on - // `[ty::PseudoRigidDueToOpaquesBound::opt_unmentioned_projection_bound]` - // for details. + // We need to support associated types of not-yet-defined opaque types. if candidates.is_empty() && let Some(ty::NormalizesTo { alias, term }) = G::as_normalizes_to(goal.predicate) && let Some(unconstrained_ty) = term.as_type() From 920e24ab291c11259ef44c0f971ccfa93feaf1fc Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 30 Sep 2026 17:00:08 +0200 Subject: [PATCH 12/12] comments --- compiler/rustc_next_trait_solver/src/solve/mod.rs | 2 ++ compiler/rustc_type_ir/src/solve/mod.rs | 3 +++ 2 files changed, 5 insertions(+) diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 9a499d12f1f14..6c1f1d3099c2f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -460,6 +460,8 @@ pub struct GoalEvaluation { pub stalled_on: Option>, } +/// A variant of [ExternalConstraintsData](rustc_type_ir::solve::ExternalConstraintsData) +/// whose fields are not interned. This is purely used as a performance optimization. #[derive_where(Clone, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] pub struct RawExternalConstraintsData { diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index dabf118718d8d..fd991cf353dc5 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -225,6 +225,9 @@ impl RerunCondition { a.union(b).map(Self::OpaqueInStorage).unwrap_or(Self::Always) } (Self::PseudoRigidInStorage, Self::PseudoRigidInStorage) => Self::PseudoRigidInStorage, + // The pseudo-rigid storage is always empty if the opaque type storage is empty, + // so "pseudo-rigid in storage x opaque type in storage" just results in + // "opaque type in storage". (Self::PseudoRigidInStorage, Self::OpaqueInStorageOrPseudoRigidInStorage(a)) | (Self::OpaqueInStorageOrPseudoRigidInStorage(a), Self::PseudoRigidInStorage) => { Self::OpaqueInStorage(a)