Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer/unify.rs')
| -rw-r--r-- | crates/hir-ty/src/infer/unify.rs | 182 |
1 files changed, 22 insertions, 160 deletions
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index b0f916b8c0..c28fea0ff1 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -3,10 +3,10 @@ use std::fmt; use base_db::Crate; -use hir_def::{AdtId, ExpressionStoreOwnerId, GenericParamId, TraitId}; +use hir_def::{ExpressionStoreOwnerId, GenericParamId, TraitId}; use rustc_hash::FxHashSet; use rustc_type_ir::{ - TyVid, TypeFoldable, TypeVisitableExt, UpcastFrom, + TyVid, TypeFoldable, TypeVisitableExt, inherent::{Const as _, GenericArg as _, IntoKind, Ty as _}, solve::Certainty, }; @@ -15,23 +15,20 @@ use smallvec::SmallVec; use crate::{ db::HirDatabase, next_solver::{ - Canonical, ClauseKind, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Goal, + Canonical, ClauseKind, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, ParamEnv, Predicate, PredicateKind, Region, SolverDefId, Term, TraitRef, Ty, TyKind, TypingMode, fulfill::{FulfillmentCtxt, NextSolverError}, infer::{ - DbInternerInferExt, InferCtxt, InferOk, InferResult, - at::{At, ToTrace}, + DbInternerInferExt, InferCtxt, InferOk, + at::At, snapshot::CombinedSnapshot, traits::{Obligation, ObligationCause, PredicateObligation}, }, inspect::{InspectConfig, InspectGoal, ProofTreeVisitor}, obligation_ctxt::ObligationCtxt, }, - traits::{ - NextTraitSolveResult, ParamEnvAndCrate, next_trait_solve_canonical_in_ctxt, - next_trait_solve_in_ctxt, - }, + traits::ParamEnvAndCrate, }; struct NestedObligationsForSelfTy<'a, 'db> { @@ -133,11 +130,6 @@ pub(crate) struct InferenceTable<'db> { pub(super) diverging_type_vars: FxHashSet<Ty<'db>>, } -pub(crate) struct InferenceTableSnapshot<'db> { - ctxt_snapshot: CombinedSnapshot, - obligations: FulfillmentCtxt<'db>, -} - impl<'db> InferenceTable<'db> { /// Inside hir-ty you should use this for inference only, and always pass `owner`. /// Outside it, always pass `owner = None`. @@ -145,14 +137,10 @@ impl<'db> InferenceTable<'db> { db: &'db dyn HirDatabase, trait_env: ParamEnv<'db>, krate: Crate, - owner: Option<ExpressionStoreOwnerId>, + owner: ExpressionStoreOwnerId, ) -> Self { let interner = DbInterner::new_with(db, krate); - let typing_mode = match owner { - Some(owner) => TypingMode::typeck_for_body(interner, owner.into()), - // IDE things wants to reveal opaque types. - None => TypingMode::PostAnalysis, - }; + let typing_mode = TypingMode::typeck_for_body(interner, owner.into()); let infer_ctxt = interner.infer_ctxt().build(typing_mode); InferenceTable { db, @@ -172,6 +160,10 @@ impl<'db> InferenceTable<'db> { self.infer_ctxt.type_is_copy_modulo_regions(self.param_env, ty) } + pub(crate) fn type_is_sized_modulo_regions(&self, ty: Ty<'db>) -> bool { + self.infer_ctxt.type_is_sized_modulo_regions(self.param_env, ty) + } + pub(crate) fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'db>) -> bool { self.infer_ctxt.type_is_use_cloned_modulo_regions(self.param_env, ty) } @@ -253,23 +245,6 @@ impl<'db> InferenceTable<'db> { self.diverging_type_vars.insert(ty); } - pub(crate) fn canonicalize<T>(&mut self, t: T) -> rustc_type_ir::Canonical<DbInterner<'db>, T> - where - T: TypeFoldable<DbInterner<'db>>, - { - // try to resolve obligations before canonicalizing, since this might - // result in new knowledge about variables - self.select_obligations_where_possible(); - self.infer_ctxt.canonicalize_response(t) - } - - pub(crate) fn normalize_alias_ty(&mut self, alias: Ty<'db>) -> Ty<'db> { - self.infer_ctxt - .at(&ObligationCause::new(), self.param_env) - .structurally_normalize_ty(alias, &mut self.fulfillment_cx) - .unwrap_or(alias) - } - pub(crate) fn next_ty_var(&self) -> Ty<'db> { self.infer_ctxt.next_ty_var() } @@ -313,17 +288,6 @@ impl<'db> InferenceTable<'db> { value.fold_with(&mut resolve_completely::Resolver::new(self, true, &mut goals)) } - /// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that. - pub(crate) fn unify<T: ToTrace<'db>>(&mut self, ty1: T, ty2: T) -> bool { - self.try_unify(ty1, ty2).map(|infer_ok| self.register_infer_ok(infer_ok)).is_ok() - } - - /// Unify two relatable values (e.g. `Ty`) and return new trait goals arising from it, so the - /// caller needs to deal with them. - pub(crate) fn try_unify<T: ToTrace<'db>>(&mut self, t1: T, t2: T) -> InferResult<'db, ()> { - self.at(&ObligationCause::new()).eq(t1, t2) - } - pub(crate) fn at<'a>(&'a self, cause: &'a ObligationCause) -> At<'a, 'db> { self.infer_ctxt.at(cause, self.param_env) } @@ -332,6 +296,10 @@ impl<'db> InferenceTable<'db> { self.infer_ctxt.shallow_resolve(ty) } + pub(crate) fn resolve_vars_if_possible<T: TypeFoldable<DbInterner<'db>>>(&self, t: T) -> T { + self.infer_ctxt.resolve_vars_if_possible(t) + } + pub(crate) fn resolve_vars_with_obligations<T>(&mut self, t: T) -> T where T: rustc_type_ir::TypeFoldable<DbInterner<'db>>, @@ -380,16 +348,13 @@ impl<'db> InferenceTable<'db> { // FIXME: Err if it still contain infer vars. } - pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot<'db> { - let ctxt_snapshot = self.infer_ctxt.start_snapshot(); - let obligations = self.fulfillment_cx.clone(); - InferenceTableSnapshot { ctxt_snapshot, obligations } + pub(crate) fn snapshot(&mut self) -> CombinedSnapshot { + self.infer_ctxt.start_snapshot() } #[tracing::instrument(skip_all)] - pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot<'db>) { - self.infer_ctxt.rollback_to(snapshot.ctxt_snapshot); - self.fulfillment_cx = snapshot.obligations; + pub(crate) fn rollback_to(&mut self, snapshot: CombinedSnapshot) { + self.infer_ctxt.rollback_to(snapshot); } pub(crate) fn commit_if_ok<T, E>( @@ -399,51 +364,12 @@ impl<'db> InferenceTable<'db> { let snapshot = self.snapshot(); let result = f(self); match result { - Ok(_) => {} - Err(_) => { - self.rollback_to(snapshot); - } + Ok(_) => self.infer_ctxt.commit_from(snapshot), + Err(_) => self.rollback_to(snapshot), } result } - /// Checks an obligation without registering it. Useful mostly to check - /// whether a trait *might* be implemented before deciding to 'lock in' the - /// choice (during e.g. method resolution or deref). - #[tracing::instrument(level = "debug", skip(self))] - pub(crate) fn try_obligation(&mut self, predicate: Predicate<'db>) -> NextTraitSolveResult { - let goal = Goal { param_env: self.param_env, predicate }; - let canonicalized = self.canonicalize(goal); - - next_trait_solve_canonical_in_ctxt(&self.infer_ctxt, canonicalized) - } - - pub(crate) fn register_obligation(&mut self, predicate: Predicate<'db>) { - let goal = Goal { param_env: self.param_env, predicate }; - self.register_obligation_in_env(goal) - } - - #[tracing::instrument(level = "debug", skip(self))] - fn register_obligation_in_env(&mut self, goal: Goal<'db, Predicate<'db>>) { - let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal); - tracing::debug!(?result); - match result { - Ok((_, Certainty::Yes)) => {} - Err(rustc_type_ir::solve::NoSolution) => {} - Ok((_, Certainty::Maybe { .. })) => { - self.fulfillment_cx.register_predicate_obligation( - &self.infer_ctxt, - Obligation::new( - self.interner(), - ObligationCause::new(), - goal.param_env, - goal.predicate, - ), - ); - } - } - } - pub(crate) fn register_bound(&mut self, ty: Ty<'db>, def_id: TraitId, cause: ObligationCause) { if !ty.references_non_lt_error() { let trait_ref = TraitRef::new(self.interner(), def_id.into(), [ty]); @@ -533,70 +459,6 @@ impl<'db> InferenceTable<'db> { pub(super) fn insert_const_vars_shallow(&mut self, c: Const<'db>) -> Const<'db> { if c.is_ct_error() { self.next_const_var() } else { c } } - - /// Check if given type is `Sized` or not - pub(crate) fn is_sized(&mut self, ty: Ty<'db>) -> bool { - fn short_circuit_trivial_tys(ty: Ty<'_>) -> Option<bool> { - match ty.kind() { - TyKind::Bool - | TyKind::Char - | TyKind::Int(_) - | TyKind::Uint(_) - | TyKind::Float(_) - | TyKind::Ref(..) - | TyKind::RawPtr(..) - | TyKind::Never - | TyKind::FnDef(..) - | TyKind::Array(..) - | TyKind::FnPtr(..) => Some(true), - TyKind::Slice(..) | TyKind::Str | TyKind::Dynamic(..) => Some(false), - _ => None, - } - } - - let mut ty = ty; - ty = self.try_structurally_resolve_type(ty); - if let Some(sized) = short_circuit_trivial_tys(ty) { - return sized; - } - - { - let mut structs = SmallVec::<[_; 8]>::new(); - // Must use a loop here and not recursion because otherwise users will conduct completely - // artificial examples of structs that have themselves as the tail field and complain r-a crashes. - while let Some((AdtId::StructId(id), subst)) = ty.as_adt() { - let struct_data = id.fields(self.db); - if let Some((last_field, _)) = struct_data.fields().iter().next_back() { - let last_field_ty = self.db.field_types(id.into())[last_field] - .get() - .instantiate(self.interner(), subst); - if structs.contains(&ty) { - // A struct recursively contains itself as a tail field somewhere. - return true; // Don't overload the users with too many errors. - } - structs.push(ty); - // Structs can have DST as its last field and such cases are not handled - // as unsized by the chalk, so we do this manually. - ty = last_field_ty; - ty = self.try_structurally_resolve_type(ty); - if let Some(sized) = short_circuit_trivial_tys(ty) { - return sized; - } - } else { - break; - }; - } - } - - let Some(sized) = self.interner().lang_items().Sized else { - return false; - }; - let sized_pred = Predicate::upcast_from( - TraitRef::new(self.interner(), sized.into(), [ty]), - self.interner(), - ); - self.try_obligation(sized_pred).certain() - } } impl fmt::Debug for InferenceTable<'_> { |