diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index d27b28dbdb214..9a4cfab3dd4d9 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -6,6 +6,7 @@ use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::relate::combine::PredicateEmittingRelation; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; +use rustc_type_ir::solve::TyOrConstInferVar; use rustc_type_ir::{TypeSuperFoldable, TypeVisitableExt}; use super::type_variable::TypeVariableValue; @@ -148,49 +149,8 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid) } - fn is_changed_arg(&self, arg: ty::GenericArg<'tcx>) -> bool { - match arg.kind() { - ty::GenericArgKind::Lifetime(_) => { - // Lifetimes should not change affect trait selection. - false - } - ty::GenericArgKind::Type(ty) => { - if let ty::Infer(infer_ty) = *ty.kind() { - match infer_ty { - ty::InferTy::TyVar(vid) => !matches!( - self.inner.borrow().try_type_variables_probe_ref(vid), - Some(TypeVariableValue::Unknown { .. }) - ), - ty::InferTy::IntVar(vid) => !matches!( - self.inner.borrow().int_unification_storage.try_probe_value(vid), - Some(ty::IntVarValue::Unknown) - ), - ty::InferTy::FloatVar(vid) => !matches!( - self.inner.borrow().float_unification_storage.try_probe_value(vid), - Some(ty::FloatVarValue::Unknown) - ), - ty::InferTy::FreshTy(_) - | ty::InferTy::FreshIntTy(_) - | ty::InferTy::FreshFloatTy(_) => true, - } - } else { - true - } - } - ty::GenericArgKind::Const(ct) => { - if let ty::ConstKind::Infer(infer_ct) = ct.kind() { - match infer_ct { - ty::InferConst::Var(vid) => !matches!( - self.inner.borrow().const_unification_storage.try_probe_value(vid), - Some(ConstVariableValue::Unknown { .. }) - ), - ty::InferConst::Fresh(_) => true, - } - } else { - true - } - } - } + fn ty_or_const_infer_var_changed(&self, var: TyOrConstInferVar) -> bool { + self.ty_or_const_infer_var_changed(var) } fn next_region_infer(&self) -> ty::Region<'tcx> { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 8ae2872f21af5..0e4dfc6854e22 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -29,14 +29,15 @@ use rustc_middle::traits::solve::Goal; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{ self, BoundVarReplacerDelegate, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, - GenericArgsRef, GenericParamDefKind, InferConst, IntVid, OpaqueTypeKey, ProvisionalHiddenType, - PseudoCanonicalInput, RegionExt, Term, TermKind, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder, + GenericArgsRef, GenericParamDefKind, InferConst, OpaqueTypeKey, ProvisionalHiddenType, + PseudoCanonicalInput, RegionExt, Term, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypingEnv, TypingMode, fold_regions, }; use rustc_span::{DUMMY_SP, Span, Symbol}; use rustc_type_ir::MayBeErased; use snapshot::undo_log::InferCtxtUndoLogs; use tracing::{debug, instrument}; +use ty::solve::TyOrConstInferVar; use type_variable::TypeVariableOrigin; use crate::infer::snapshot::undo_log::UndoLog; @@ -1616,44 +1617,24 @@ impl<'tcx> InferCtxt<'tcx> { /// inference variables), and it handles both `Ty` and `ty::Const` without /// having to resort to storing full `GenericArg`s in `stalled_on`. #[inline(always)] - pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar) -> bool { - match infer_var { - TyOrConstInferVar::Ty(v) => { - use self::type_variable::TypeVariableValue; - - // If `inlined_probe` returns a `Known` value, it never equals - // `ty::Infer(ty::TyVar(v))`. - match self.inner.borrow_mut().type_variables().inlined_probe(v) { - TypeVariableValue::Unknown { .. } => false, - TypeVariableValue::Known { .. } => true, - } - } - - TyOrConstInferVar::TyInt(v) => { - // If `inlined_probe_value` returns a value it's always a - // `ty::Int(_)` or `ty::UInt(_)`, which never matches a - // `ty::Infer(_)`. - self.inner.borrow_mut().int_unification_table().inlined_probe_value(v).is_known() - } - - TyOrConstInferVar::TyFloat(v) => { - // If `probe_value` returns a value it's always a - // `ty::Float(_)`, which never matches a `ty::Infer(_)`. - // - // Not `inlined_probe_value(v)` because this call site is colder. - self.inner.borrow_mut().float_unification_table().probe_value(v).is_known() - } - - TyOrConstInferVar::Const(v) => { - // If `probe_value` returns a `Known` value, it never equals - // `ty::ConstKind::Infer(ty::InferConst::Var(v))`. - // - // Not `inlined_probe_value(v)` because this call site is colder. - match self.inner.borrow_mut().const_unification_table().probe_value(v) { - ConstVariableValue::Unknown { .. } => false, - ConstVariableValue::Known { .. } => true, - } - } + pub fn ty_or_const_infer_var_changed(&self, var: TyOrConstInferVar) -> bool { + match var { + TyOrConstInferVar::Ty(vid) => !matches!( + self.inner.borrow().try_type_variables_probe_ref(vid), + Some(TypeVariableValue::Unknown { .. }) + ), + TyOrConstInferVar::TyInt(vid) => !matches!( + self.inner.borrow().int_unification_storage.try_probe_value(vid), + Some(ty::IntVarValue::Unknown) + ), + TyOrConstInferVar::TyFloat(vid) => !matches!( + self.inner.borrow().float_unification_storage.try_probe_value(vid), + Some(ty::FloatVarValue::Unknown) + ), + TyOrConstInferVar::Const(vid) => !matches!( + self.inner.borrow().const_unification_storage.try_probe_value(vid), + Some(ConstVariableValue::Unknown { .. }) + ), } } @@ -1667,64 +1648,6 @@ impl<'tcx> InferCtxt<'tcx> { } } -/// Helper for [InferCtxt::ty_or_const_infer_var_changed] (see comment on that), currently -/// used only for `traits::fulfill`'s list of `stalled_on` inference variables. -#[derive(Copy, Clone, Debug)] -pub enum TyOrConstInferVar { - /// Equivalent to `ty::Infer(ty::TyVar(_))`. - Ty(TyVid), - /// Equivalent to `ty::Infer(ty::IntVar(_))`. - TyInt(IntVid), - /// Equivalent to `ty::Infer(ty::FloatVar(_))`. - TyFloat(FloatVid), - - /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`. - Const(ConstVid), -} - -impl<'tcx> TyOrConstInferVar { - /// Tries to extract an inference variable from a type or a constant, returns `None` - /// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`) and - /// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`). - pub fn maybe_from_generic_arg(arg: GenericArg<'tcx>) -> Option { - match arg.kind() { - GenericArgKind::Type(ty) => Self::maybe_from_ty(ty), - GenericArgKind::Const(ct) => Self::maybe_from_const(ct), - GenericArgKind::Lifetime(_) => None, - } - } - - /// Tries to extract an inference variable from a type or a constant, returns `None` - /// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`) and - /// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`). - pub fn maybe_from_term(term: Term<'tcx>) -> Option { - match term.kind() { - TermKind::Ty(ty) => Self::maybe_from_ty(ty), - TermKind::Const(ct) => Self::maybe_from_const(ct), - } - } - - /// Tries to extract an inference variable from a type, returns `None` - /// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`). - fn maybe_from_ty(ty: Ty<'tcx>) -> Option { - match *ty.kind() { - ty::Infer(ty::TyVar(v)) => Some(TyOrConstInferVar::Ty(v)), - ty::Infer(ty::IntVar(v)) => Some(TyOrConstInferVar::TyInt(v)), - ty::Infer(ty::FloatVar(v)) => Some(TyOrConstInferVar::TyFloat(v)), - _ => None, - } - } - - /// Tries to extract an inference variable from a constant, returns `None` - /// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`). - fn maybe_from_const(ct: ty::Const<'tcx>) -> Option { - match ct.kind() { - ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)), - _ => None, - } - } -} - /// Replace `{integer}` with `i32` and `{float}` with `f64`. /// Used only for diagnostics. struct InferenceLiteralEraser<'tcx> { 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 5a1e864bfd7df..299eeda404878 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 @@ -51,7 +51,7 @@ where // If any of the stalled goal's generic arguments changed, // rerunning might make progress so we should rerun. - if stalled_vars.iter().any(|value| delegate.is_changed_arg(*value)) { + if stalled_vars.iter().any(|value| delegate.ty_or_const_infer_var_changed(*value)) { return MayMakeProgress; } 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 68fc54605754d..ba06f8a2a0193 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 @@ -12,7 +12,7 @@ use rustc_type_ir::search_graph::{CandidateHeadUsages, LowerAvailableDepth, Path use rustc_type_ir::solve::{ AccessedOpaques, ExternalRegionConstraints, FetchEligibleAssocItemResponse, MaybeInfo, NoSolutionOrRerunNonErased, OpaqueTypesJank, QueryResultOrRerunNonErased, RerunCondition, - RerunNonErased, RerunReason, RerunResultExt, SmallCopySet, + RerunNonErased, RerunReason, RerunResultExt, SmallCopySet, TyOrConstInferVar, }; use rustc_type_ir::{ self as ty, CanonicalVarValues, ClauseKind, InferCtxtLike, Interner, MayBeErased, @@ -839,29 +839,35 @@ where &self, canonical_goal: CanonicalInput, certainty: Certainty, - mut stalled_vars: ThinVec, + stalled_vars: ThinVec, previously_succeeded_in_erased: SucceededInErased, ) -> GoalStalledOn { // Remove the canonicalized universal vars, since we only care about stalled existentials. let mut sub_roots = ThinVec::new(); - stalled_vars.retain(|arg| match arg.kind() { - // Lifetimes can never stall goals. - ty::GenericArgKind::Lifetime(_) => false, - ty::GenericArgKind::Type(ty) => match ty.kind() { - ty::Infer(ty::TyVar(vid)) => { - sub_roots.push(self.delegate.sub_unification_table_root_var(vid)); - true - } - ty::Infer(_) => true, - ty::Param(_) | ty::Placeholder(_) => false, - _ => unreachable!("unexpected orig_value: {ty:?}"), - }, - ty::GenericArgKind::Const(ct) => match ct.kind() { - ty::ConstKind::Infer(_) => true, - ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(_) => false, - _ => unreachable!("unexpected orig_value: {ct:?}"), - }, - }); + let stalled_vars = stalled_vars + .into_iter() + .filter_map(|arg| match arg.kind() { + // Lifetimes can never stall goals. + ty::GenericArgKind::Lifetime(_) => None, + ty::GenericArgKind::Type(ty) => match ty.kind() { + ty::Infer(ty::TyVar(vid)) => { + sub_roots.push(self.delegate.sub_unification_table_root_var(vid)); + Some(TyOrConstInferVar::Ty(vid)) + } + ty::Infer(ty::IntVar(vid)) => Some(TyOrConstInferVar::TyInt(vid)), + ty::Infer(ty::FloatVar(vid)) => Some(TyOrConstInferVar::TyFloat(vid)), + ty::Param(_) | ty::Placeholder(_) => None, + _ => unreachable!("unexpected orig_value: {ty:?}"), + }, + ty::GenericArgKind::Const(ct) => match ct.kind() { + ty::ConstKind::Infer(ty::InferConst::Var(v)) => { + Some(TyOrConstInferVar::Const(v)) + } + ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(_) => None, + _ => unreachable!("unexpected orig_value: {ct:?}"), + }, + }) + .collect(); GoalStalledOn { stalled_vars, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index f9b484cc6cadd..1a66ddb8e2238 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -19,6 +19,7 @@ use rustc_middle::ty::{ IsSuggestable, Term, TermKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, TypeckResults, }; +use rustc_next_trait_solver::solve::TyOrConstInferVar; use rustc_span::{BytePos, DUMMY_SP, Ident, Span, sym}; use tracing::{debug, instrument, warn}; @@ -28,7 +29,7 @@ use crate::diagnostics::{ SpecifyGenericParamsSuggestion, }; use crate::error_reporting::TypeErrCtxt; -use crate::infer::{InferCtxt, TyOrConstInferVar}; +use crate::infer::InferCtxt; pub enum TypeAnnotationNeeded { /// ```compile_fail,E0282 @@ -94,7 +95,7 @@ impl InferenceDiagnosticsData { } else { match displayed_ty .walk() - .filter_map(TyOrConstInferVar::maybe_from_generic_arg) + .filter_map(TyOrConstInferVar::maybe_from_generic_arg::>) .take(2) .count() { diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 4f8bac36abb6f..908b3452fc743 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -19,7 +19,7 @@ use rustc_middle::ty::{ self, MayBeErased, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, }; -use rustc_next_trait_solver::solve::{GoalStalledOn, GoalStalledOnOpaques}; +use rustc_next_trait_solver::solve::{GoalStalledOn, GoalStalledOnOpaques, TyOrConstInferVar}; use rustc_span::{DUMMY_SP, Span}; use thin_vec::{ThinVec, thin_vec}; @@ -55,7 +55,7 @@ impl<'tcx> SolverDelegate<'tcx> { /// Create a [`ComputeGoalFastPathOutcome`] signalling the goal is stalled /// on a list of [`ty::GenericArg`] fn goal_stalled_on_args<'tcx>( - stalled_vars: ThinVec>, + stalled_vars: ThinVec, ) -> ComputeGoalFastPathOutcome<'tcx> { ComputeGoalFastPathOutcome::TriviallyStalled { stalled_on: GoalStalledOn { @@ -71,7 +71,7 @@ fn goal_stalled_on_args<'tcx>( /// on a list of [`ty::GenericArg`] *or* the opaque type storage being nonempty. /// fn goal_stalled_on_args_or_nonempty_opaques<'tcx>( - stalled_vars: ThinVec>, + stalled_vars: ThinVec, ) -> ComputeGoalFastPathOutcome<'tcx> { ComputeGoalFastPathOutcome::TriviallyStalled { stalled_on: GoalStalledOn { @@ -156,14 +156,14 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< let trait_pred = pred.rebind(trait_pred); let self_ty = self.shallow_resolve(trait_pred.self_ty().skip_binder()); - if self_ty.is_ty_var() + if let Some(vid) = self_ty.ty_vid() // We don't do this fast path when opaques are defined since we may // eventually use opaques to incompletely guide inference via ty var // self types. // FIXME: Properly consider opaques here. && self.known_no_opaque_types_in_storage() { - goal_stalled_on_args_or_nonempty_opaques(thin_vec![self_ty.into()]) + goal_stalled_on_args_or_nonempty_opaques(thin_vec![TyOrConstInferVar::Ty(vid)]) } else if trait_pred.polarity() == ty::PredicatePolarity::Positive { match self.0.tcx.as_lang_item(trait_pred.def_id()) { Some(LangItem::Sized) | Some(LangItem::MetaSized) => { @@ -226,7 +226,15 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< ty.visit_with(&mut infer_collector); let infers = infer_collector.infers; if !infers.is_empty() { - return goal_stalled_on_args(infers); + return goal_stalled_on_args( + infers + .into_iter() + .map(|i| { + TyOrConstInferVar::maybe_from_generic_arg::(i) + .unwrap() + }) + .collect(), + ); } if ty.has_non_rigid_aliases() { @@ -250,7 +258,10 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< match (self.shallow_resolve(a).kind(), self.shallow_resolve(b).kind()) { (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => { self.sub_unify_ty_vids_raw(a_vid, b_vid); - goal_stalled_on_args(thin_vec![a.into(), b.into()]) + goal_stalled_on_args(thin_vec![ + TyOrConstInferVar::Ty(a_vid), + TyOrConstInferVar::Ty(b_vid), + ]) } _ => Outcome::NoFastPath, } @@ -261,8 +272,8 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< } let arg = self.shallow_resolve_const(ct); - if arg.is_ct_infer() { - goal_stalled_on_args(thin_vec![arg.into()]) + if let Some(vid) = arg.ct_vid() { + goal_stalled_on_args(thin_vec![TyOrConstInferVar::Const(vid)]) } else { Outcome::NoFastPath } @@ -276,7 +287,10 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< if arg.is_trivially_wf(self.tcx) { Outcome::TriviallyHolds } else if arg.is_infer() { - goal_stalled_on_args(thin_vec![arg.into_arg()]) + goal_stalled_on_args(thin_vec![ + TyOrConstInferVar::maybe_from_term::>(arg) + .expect("its an infer var"), + ]) } else { Outcome::NoFastPath } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index da596fe3b44b0..b3b8337a81f6a 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -326,7 +326,7 @@ where // Conservative here: if a stalled var no longer resolves to an // infer var, some unification happened, so the goal is no longer // stalled. Include it to be re-evaluated downstream. - stalled_on.stalled_vars.iter().filter_map(|arg| arg.as_type()).any(|ty| { + stalled_on.stalled_vars.iter().filter_map(|arg| arg.as_type(infcx.tcx)).any(|ty| { match *infcx.shallow_resolve(ty).kind() { ty::Infer(ty::TyVar(tv)) => infcx.sub_unification_table_root_var(tv) == vid, _ => true, @@ -351,7 +351,7 @@ where stalled_on .stalled_vars .iter() - .filter_map(|arg| arg.as_type()) + .filter_map(|arg| arg.as_type(infcx.tcx)) .any(|ty| matches!(infcx.shallow_resolve(ty).kind(), ty::Infer(ty::FloatVar(_)))) }) } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 3b111ab31575e..d0452052f10f6 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -17,6 +17,7 @@ use rustc_middle::ty::{ self, Binder, Const, DelayedSet, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, may_use_unstable_feature, }; +use rustc_next_trait_solver::solve::TyOrConstInferVar; use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, debug_span, instrument}; @@ -28,7 +29,7 @@ use super::{ ScrubbedTraitError, const_evaluatable, wf, }; use crate::error_reporting::InferCtxtErrorExt; -use crate::infer::{InferCtxt, TyOrConstInferVar}; +use crate::infer::InferCtxt; use crate::traits::normalize::normalize_with_depth_to; use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _}; use crate::traits::query::evaluate_obligation::InferCtxtExt; @@ -617,8 +618,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { obligation.cause.span, ) { None => { - pending_obligation.stalled_on = - vec![TyOrConstInferVar::maybe_from_term(term).unwrap()]; + pending_obligation.stalled_on = vec![ + TyOrConstInferVar::maybe_from_term::>(term).unwrap(), + ]; ProcessResult::Unchanged } Some(os) => ProcessResult::Changed(mk_pending(obligation, os)), @@ -683,11 +685,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { Ok(()) => ProcessResult::Changed(Default::default()), Err(NotConstEvaluatable::MentionsInfer) => { pending_obligation.stalled_on.clear(); - pending_obligation.stalled_on.extend( - alias_const - .walk() - .filter_map(TyOrConstInferVar::maybe_from_generic_arg), - ); + pending_obligation.stalled_on.extend(alias_const.walk().filter_map( + TyOrConstInferVar::maybe_from_generic_arg::>, + )); ProcessResult::Unchanged } Err( @@ -767,12 +767,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ) { Ok(val) => Ok(val), e @ Err(EvaluateConstErr::HasGenericsOrInfers) => { - stalled_on.extend( - alias_const - .args - .iter() - .filter_map(TyOrConstInferVar::maybe_from_generic_arg), - ); + stalled_on.extend(alias_const.args.iter().filter_map( + TyOrConstInferVar::maybe_from_generic_arg::>, + )); e } e @ Err( @@ -1044,7 +1041,7 @@ fn args_infer_vars<'tcx>( } walker.visited.into_iter() }) - .filter_map(TyOrConstInferVar::maybe_from_generic_arg) + .filter_map(TyOrConstInferVar::maybe_from_generic_arg::>) } #[derive(Debug)] diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index b84b029bc155f..1cd070365f651 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -9,7 +9,7 @@ use crate::data_structures::DelayedMap; use crate::inherent::*; use crate::relate::RelateResult; use crate::relate::combine::PredicateEmittingRelation; -use crate::solve::VisibleForLeakCheck; +use crate::solve::{TyOrConstInferVar, VisibleForLeakCheck}; use crate::{ self as ty, Interner, Region, TyVid, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, @@ -422,7 +422,7 @@ pub trait InferCtxtLike: Sized { ) -> ::Const; fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> Region; - fn is_changed_arg(&self, arg: ::GenericArg) -> bool; + fn ty_or_const_infer_var_changed(&self, var: TyOrConstInferVar) -> bool; fn next_region_infer(&self) -> Region; fn next_ty_infer(&self) -> ::Ty; diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 303476fa11694..3f5ad1ed9a8f5 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -13,11 +13,13 @@ use rustc_type_ir_macros::{ use thin_vec::ThinVec; use tracing::debug; +use crate::inherent::*; use crate::lang_items::SolverTraitLangItem; use crate::region_constraint::RegionConstraint; use crate::search_graph::PathKind; use crate::{ - self as ty, Canonical, CanonicalVarValues, CantBeErased, Interner, TyVid, TypingMode, Upcast, + self as ty, Canonical, CanonicalVarValues, CantBeErased, ConstVid, FloatVid, GenericArgKind, + InferConst, IntVid, Interner, TermKind, TyVid, TypingMode, Upcast, }; pub type CanonicalInput::Predicate> = @@ -988,7 +990,7 @@ pub enum GoalStalledOnOpaques { #[derive_where(Clone, Debug; I: Interner)] pub struct GoalStalledOn { // `ThinVec` is important for performance. See #160005. - pub stalled_vars: ThinVec, + pub stalled_vars: ThinVec, // `ThinVec` is important for performance. See #160005. pub sub_roots: ThinVec, /// The certainty that will be returned on subsequent evaluations if this @@ -999,7 +1001,6 @@ pub struct GoalStalledOn { /// For some goals we can trivially answer some questions without going through /// canonicalization. There are three options: - #[derive(Clone, Debug)] pub enum ComputeGoalFastPathOutcome { /// Do not attempt the fast path. Compute as normal. @@ -1010,3 +1011,68 @@ pub enum ComputeGoalFastPathOutcome { /// now, but can return information about what its stalled on and when it can be computed for real. TriviallyStalled { stalled_on: GoalStalledOn }, } + +/// Helper for `InferCtxt::ty_or_const_infer_var_changed` (see comment on that), currently +/// used only for `traits::fulfill`'s list of `stalled_on` inference variables. +#[derive(Copy, Clone, Debug)] +pub enum TyOrConstInferVar { + /// Equivalent to `ty::Infer(ty::TyVar(_))`. + Ty(TyVid), + /// Equivalent to `ty::Infer(ty::IntVar(_))`. + TyInt(IntVid), + /// Equivalent to `ty::Infer(ty::FloatVar(_))`. + TyFloat(FloatVid), + + /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`. + Const(ConstVid), +} + +impl TyOrConstInferVar { + pub fn as_type(&self, interner: I) -> Option { + match self { + Self::Ty(vid) => Some(I::Ty::new_var(interner, *vid)), + Self::TyInt(_) | Self::TyFloat(_) | Self::Const(_) => None, + } + } + + /// Tries to extract an inference variable from a type or a constant, returns `None` + /// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`) and + /// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`). + pub fn maybe_from_generic_arg(arg: I::GenericArg) -> Option { + match arg.kind() { + GenericArgKind::Type(ty) => Self::maybe_from_ty::(ty), + GenericArgKind::Const(ct) => Self::maybe_from_const::(ct), + GenericArgKind::Lifetime(_) => None, + } + } + + /// Tries to extract an inference variable from a type or a constant, returns `None` + /// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`) and + /// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`). + pub fn maybe_from_term(term: I::Term) -> Option { + match term.kind() { + TermKind::Ty(ty) => Self::maybe_from_ty::(ty), + TermKind::Const(ct) => Self::maybe_from_const::(ct), + } + } + + /// Tries to extract an inference variable from a type, returns `None` + /// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`). + fn maybe_from_ty(ty: I::Ty) -> Option { + match ty.kind() { + ty::Infer(ty::TyVar(v)) => Some(TyOrConstInferVar::Ty(v)), + ty::Infer(ty::IntVar(v)) => Some(TyOrConstInferVar::TyInt(v)), + ty::Infer(ty::FloatVar(v)) => Some(TyOrConstInferVar::TyFloat(v)), + _ => None, + } + } + + /// Tries to extract an inference variable from a constant, returns `None` + /// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`). + fn maybe_from_const(ct: I::Const) -> Option { + match ct.kind() { + ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)), + _ => None, + } + } +}