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 | 472 |
1 files changed, 230 insertions, 242 deletions
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index 3745d2c98f..ec4b7ee85d 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -3,7 +3,8 @@ use std::{fmt, mem}; use chalk_ir::{ - cast::Cast, fold::TypeFoldable, interner::HasInterner, CanonicalVarKind, FloatTy, IntTy, TyVariableKind, + CanonicalVarKind, FloatTy, IntTy, TyVariableKind, cast::Cast, fold::TypeFoldable, + interner::HasInterner, }; use either::Either; use hir_def::{AdtId, lang_item::LangItem}; @@ -11,13 +12,36 @@ use hir_expand::name::Name; use intern::sym; use rustc_hash::{FxHashMap, FxHashSet}; use rustc_next_trait_solver::solve::HasChanged; -use rustc_type_ir::{inherent::Span, relate::{solver_relating::RelateExt, Relate}, solve::{Certainty, NoSolution}, FloatVid, IntVid, TyVid}; +use rustc_type_ir::{ + AliasRelationDirection, FloatVid, IntVid, TyVid, + inherent::{Span, Term as _}, + relate::{Relate, solver_relating::RelateExt}, + solve::{Certainty, NoSolution}, +}; use smallvec::SmallVec; use triomphe::Arc; use super::{InferOk, InferResult, InferenceContext, TypeError}; use crate::{ - consteval::unknown_const, db::HirDatabase, fold_generic_args, fold_tys_and_consts, next_solver::{infer::{canonical::canonicalizer::OriginalQueryValues, snapshot::CombinedSnapshot, DbInternerInferExt, InferCtxt}, mapping::{ChalkToNextSolver, InferenceVarExt}, DbInterner, ParamEnvAnd, SolverDefIds}, to_chalk_trait_id, traits::{next_trait_solve, next_trait_solve_canonical, next_trait_solve_in_ctxt, FnTrait, NextTraitSolveResult}, AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, DomainGoal, GenericArg, GenericArgData, Goal, GoalData, InEnvironment, InferenceVar, Interner, Lifetime, OpaqueTyId, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, VariableKind, WhereClause + AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, DomainGoal, + GenericArg, GenericArgData, Goal, GoalData, InEnvironment, InferenceVar, Interner, Lifetime, + OpaqueTyId, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Substitution, TraitEnvironment, + TraitRef, Ty, TyBuilder, TyExt, TyKind, VariableKind, WhereClause, + consteval::unknown_const, + db::HirDatabase, + fold_generic_args, fold_tys_and_consts, + next_solver::{ + self, Binder, DbInterner, ParamEnvAnd, Predicate, PredicateKind, SolverDefIds, Term, + infer::{ + DbInternerInferExt, InferCtxt, canonical::canonicalizer::OriginalQueryValues, + snapshot::CombinedSnapshot, + }, + mapping::{ChalkToNextSolver, InferenceVarExt, NextSolverToChalk}, + }, + to_chalk_trait_id, + traits::{ + FnTrait, NextTraitSolveResult, next_trait_solve_canonical_in_ctxt, next_trait_solve_in_ctxt, + }, }; impl<'db> InferenceContext<'db> { @@ -38,7 +62,7 @@ impl<'db> InferenceContext<'db> { let pending_obligations = mem::take(&mut self.table.pending_obligations); let obligations = pending_obligations .iter() - .filter_map(|obligation| match obligation.goal.data(Interner) { + .filter_map(|obligation| match obligation.to_chalk(self.table.interner).goal.data(Interner) { GoalData::DomainGoal(DomainGoal::Holds(clause)) => { let ty = match clause { WhereClause::AliasEq(AliasEq { @@ -67,51 +91,6 @@ impl<'db> InferenceContext<'db> { } } -#[derive(Debug, Clone)] -pub(crate) struct Canonicalized<T> -where - T: HasInterner<Interner = Interner>, -{ - pub(crate) value: Canonical<T>, - free_vars: Vec<GenericArg>, -} - -impl<T: HasInterner<Interner = Interner>> Canonicalized<T> { - pub(crate) fn apply_solution( - &self, - ctx: &mut InferenceTable<'_>, - solution: Canonical<Substitution>, - ) { - // the solution may contain new variables, which we need to convert to new inference vars - let new_vars = Substitution::from_iter( - Interner, - solution.binders.iter(Interner).map(|k| match &k.kind { - VariableKind::Ty(TyVariableKind::General) => ctx.new_type_var().cast(Interner), - VariableKind::Ty(TyVariableKind::Integer) => ctx.new_integer_var().cast(Interner), - VariableKind::Ty(TyVariableKind::Float) => ctx.new_float_var().cast(Interner), - // Chalk can sometimes return new lifetime variables. We just replace them by errors - // for now. - VariableKind::Lifetime => ctx.new_lifetime_var().cast(Interner), - VariableKind::Const(ty) => ctx.new_const_var(ty.clone()).cast(Interner), - }), - ); - for (i, v) in solution.value.iter(Interner).enumerate() { - let var = &self.free_vars[i]; - if let Some(ty) = v.ty(Interner) { - // eagerly replace projections in the type; we may be getting types - // e.g. from where clauses where this hasn't happened yet - let ty = ctx.normalize_associated_types_in(new_vars.apply(ty.clone(), Interner)); - tracing::debug!("unifying {:?} {:?}", var, ty); - ctx.unify(var.assert_ty_ref(Interner), &ty); - } else { - let v = new_vars.apply(v.clone(), Interner); - tracing::debug!("try_unifying {:?} {:?}", var, v); - let _ = ctx.try_unify(var, &v); - } - } - } -} - /// Check if types unify. /// /// Note that we consider placeholder types to unify with everything. @@ -207,23 +186,21 @@ bitflags::bitflags! { } } -type ChalkInferenceTable = chalk_solve::infer::InferenceTable<Interner>; - #[derive(Clone)] pub(crate) struct InferenceTable<'a> { pub(crate) db: &'a dyn HirDatabase, pub(crate) interner: DbInterner<'a>, pub(crate) trait_env: Arc<TraitEnvironment>, pub(crate) tait_coercion_table: Option<FxHashMap<OpaqueTyId, Ty>>, - infer_ctxt: InferCtxt<'a>, + pub(crate) infer_ctxt: InferCtxt<'a>, diverging_tys: FxHashSet<Ty>, - pending_obligations: Vec<InEnvironment<Goal>>, + pending_obligations: Vec<next_solver::Goal<'a, next_solver::Predicate<'a>>>, } -pub(crate) struct InferenceTableSnapshot { +pub(crate) struct InferenceTableSnapshot<'a> { ctxt_snapshot: CombinedSnapshot, diverging_tys: FxHashSet<Ty>, - pending_obligations: Vec<InEnvironment<Goal>>, + pending_obligations: Vec<next_solver::Goal<'a, next_solver::Predicate<'a>>>, } impl<'a> InferenceTable<'a> { @@ -234,7 +211,9 @@ impl<'a> InferenceTable<'a> { interner, trait_env, tait_coercion_table: None, - infer_ctxt: interner.infer_ctxt().build(rustc_type_ir::TypingMode::Analysis { defining_opaque_types_and_generators: SolverDefIds::new_from_iter(interner, []) }), + infer_ctxt: interner.infer_ctxt().build(rustc_type_ir::TypingMode::Analysis { + defining_opaque_types_and_generators: SolverDefIds::new_from_iter(interner, []), + }), diverging_tys: FxHashSet::default(), pending_obligations: Vec::new(), } @@ -250,40 +229,55 @@ impl<'a> InferenceTable<'a> { let mut new_tys = FxHashSet::default(); for ty in self.diverging_tys.iter() { match ty.kind(Interner) { - TyKind::InferenceVar(var, kind) => { - match kind { - TyVariableKind::General => { - let root = InferenceVar::from(self.infer_ctxt.root_var(TyVid::from_u32(var.index())).as_u32()); - if root.index() != var.index() { - new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner)); - } + TyKind::InferenceVar(var, kind) => match kind { + TyVariableKind::General => { + let root = InferenceVar::from( + self.infer_ctxt.root_var(TyVid::from_u32(var.index())).as_u32(), + ); + if root.index() != var.index() { + new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner)); } - TyVariableKind::Integer => { - let root = InferenceVar::from(self.infer_ctxt.inner.borrow_mut().int_unification_table().find(IntVid::from_usize(var.index() as usize)).as_u32()); - if root.index() != var.index() { - new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner)); - } + } + TyVariableKind::Integer => { + let root = InferenceVar::from( + self.infer_ctxt + .inner + .borrow_mut() + .int_unification_table() + .find(IntVid::from_usize(var.index() as usize)) + .as_u32(), + ); + if root.index() != var.index() { + new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner)); } - TyVariableKind::Float => { - let root = InferenceVar::from(self.infer_ctxt.inner.borrow_mut().float_unification_table().find(FloatVid::from_usize(var.index() as usize)).as_u32()); - if root.index() != var.index() { - new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner)); - } + } + TyVariableKind::Float => { + let root = InferenceVar::from( + self.infer_ctxt + .inner + .borrow_mut() + .float_unification_table() + .find(FloatVid::from_usize(var.index() as usize)) + .as_u32(), + ); + if root.index() != var.index() { + new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner)); } } - } + }, _ => {} } } - self.diverging_tys.extend(new_tys.into_iter()); + self.diverging_tys.extend(new_tys); } - pub(super) fn set_diverging(&mut self, iv: InferenceVar, kind: TyVariableKind, diverging: bool) { + pub(super) fn set_diverging(&mut self, iv: InferenceVar, kind: TyVariableKind) { self.diverging_tys.insert(TyKind::InferenceVar(iv, kind).intern(Interner)); } fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty { - let is_diverging = self.diverging_tys.contains(&TyKind::InferenceVar(iv, kind).intern(Interner)); + let is_diverging = + self.diverging_tys.contains(&TyKind::InferenceVar(iv, kind).intern(Interner)); if is_diverging { return TyKind::Never.intern(Interner); } @@ -295,19 +289,6 @@ impl<'a> InferenceTable<'a> { .intern(Interner) } - pub(crate) fn canonicalize_with_free_vars<T>(&mut self, t: ParamEnvAnd<'a, T>) -> (rustc_type_ir::Canonical<DbInterner<'a>, ParamEnvAnd<'a, T>>, OriginalQueryValues<'a>) - where - T: rustc_type_ir::TypeFoldable<DbInterner<'a>>, - { - // try to resolve obligations before canonicalizing, since this might - // result in new knowledge about variables - self.resolve_obligations_as_possible(); - - let mut orig_values = OriginalQueryValues::default(); - let result = self.infer_ctxt.canonicalize_query(t, &mut orig_values); - (result.canonical, orig_values) - } - pub(crate) fn canonicalize<T>(&mut self, t: T) -> rustc_type_ir::Canonical<DbInterner<'a>, T> where T: rustc_type_ir::TypeFoldable<DbInterner<'a>>, @@ -341,7 +322,7 @@ impl<'a> InferenceTable<'a> { self.resolve_ty_shallow(&ty) } TyKind::AssociatedType(id, subst) => { - return Either::Left(self.resolve_ty_shallow(&ty)); + // return Either::Left(self.resolve_ty_shallow(&ty)); if ty.data(Interner).flags.intersects( chalk_ir::TypeFlags::HAS_TY_INFER | chalk_ir::TypeFlags::HAS_CT_INFER, @@ -365,51 +346,44 @@ impl<'a> InferenceTable<'a> { ); let in_env = InEnvironment::new(&self.trait_env.env, goal); let goal = in_env.to_nextsolver(self.interner); - let goal = ParamEnvAnd { param_env: goal.param_env, value: goal.predicate }; + let goal = + ParamEnvAnd { param_env: goal.param_env, value: goal.predicate }; - let (canonical_goal, _orig_values) = { + let (canonical_goal, orig_values) = { let mut orig_values = OriginalQueryValues::default(); - let result = self.infer_ctxt.canonicalize_query(goal, &mut orig_values); + let result = + self.infer_ctxt.canonicalize_query(goal, &mut orig_values); (result.canonical, orig_values) }; let canonical_goal = rustc_type_ir::Canonical { max_universe: canonical_goal.max_universe, variables: canonical_goal.variables, - value: crate::next_solver::Goal { param_env: canonical_goal.value.param_env, predicate: canonical_goal.value.value }, + value: crate::next_solver::Goal { + param_env: canonical_goal.value.param_env, + predicate: canonical_goal.value.value, + }, }; - let solution = next_trait_solve_canonical( - self.db, - self.trait_env.krate, - self.trait_env.block, - canonical_goal.clone(), + let solution = next_trait_solve_canonical_in_ctxt( + &self.infer_ctxt, + canonical_goal, ); if let NextTraitSolveResult::Certain(canonical_subst) = solution { - // This is not great :) But let's just assert this for now and come back to it later. - if canonical_subst.value.subst.len(Interner) != 1 { + let subst = self.instantiate_canonical(canonical_subst).subst; + if subst.len(Interner) != orig_values.var_values.len() { ty } else { - let normalized = canonical_subst.value.subst.as_slice(Interner) - [0] - .assert_ty_ref(Interner); - match normalized.kind(Interner) { - TyKind::Alias(AliasTy::Projection(proj_ty)) => { - if id == &proj_ty.associated_ty_id - && subst == &proj_ty.substitution - { - ty - } else { - normalized.clone() - } - } - TyKind::AssociatedType(new_id, new_subst) => { - if new_id == id && new_subst == subst { - ty + let target_ty = var.to_nextsolver(self.interner); + subst + .iter(Interner) + .zip(orig_values.var_values.iter()) + .find_map(|(new, orig)| { + if orig.ty() == Some(target_ty) { + Some(new.assert_ty_ref(Interner).clone()) } else { - normalized.clone() + None } - } - _ => normalized.clone(), - } + }) + .unwrap_or(ty) } } else { ty @@ -504,8 +478,8 @@ impl<'a> InferenceTable<'a> { pub(crate) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { let var = self.new_type_var(); let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() }; - let obligation = alias_eq.cast(Interner); - self.register_obligation(obligation); + let obligation: Goal = alias_eq.cast(Interner); + self.register_obligation(obligation.to_nextsolver(self.interner)); var } @@ -575,7 +549,9 @@ impl<'a> InferenceTable<'a> { Substitution::from_iter( Interner, binders.iter().map(|kind| match &kind.kind { - chalk_ir::VariableKind::Ty(ty_variable_kind) => self.new_var(*ty_variable_kind, false).cast(Interner), + chalk_ir::VariableKind::Ty(ty_variable_kind) => { + self.new_var(*ty_variable_kind, false).cast(Interner) + } chalk_ir::VariableKind::Lifetime => self.new_lifetime_var().cast(Interner), chalk_ir::VariableKind::Const(ty) => self.new_const_var(ty.clone()).cast(Interner), }), @@ -589,8 +565,11 @@ impl<'a> InferenceTable<'a> { let subst = self.fresh_subst(canonical.binders.as_slice(Interner)); subst.apply(canonical.value, Interner) } - - pub(crate) fn instantiate_canonical_ns<T>(&mut self, canonical: rustc_type_ir::Canonical<DbInterner<'a>, T>) -> T + + pub(crate) fn instantiate_canonical_ns<T>( + &mut self, + canonical: rustc_type_ir::Canonical<DbInterner<'a>, T>, + ) -> T where T: rustc_type_ir::TypeFoldable<DbInterner<'a>>, { @@ -605,7 +584,7 @@ impl<'a> InferenceTable<'a> { where T: HasInterner<Interner = Interner> + TypeFoldable<Interner>, { - let mut var_stack = &mut vec![]; + let var_stack = &mut vec![]; t.fold_with( &mut resolve::Resolver { table: self, var_stack, fallback }, DebruijnIndex::INNERMOST, @@ -618,6 +597,7 @@ impl<'a> InferenceTable<'a> { { let t = self.resolve_with_fallback(t, &|_, _, d, _| d); let t = self.normalize_associated_types_in(t); + // let t = self.resolve_opaque_tys_in(t); // Resolve again, because maybe normalization inserted infer vars. self.resolve_with_fallback(t, &|_, _, d, _| d) } @@ -650,7 +630,7 @@ impl<'a> InferenceTable<'a> { } let float_vars = self.infer_ctxt.inner.borrow_mut().float_unification_table().len(); for v in 0..float_vars { - let var = InferenceVar::from(v as u32).to_ty(Interner, TyVariableKind::Integer); + let var = InferenceVar::from(v as u32).to_ty(Interner, TyVariableKind::Float); let maybe_resolved = self.resolve_ty_shallow(&var); if let TyKind::InferenceVar(_, kind) = maybe_resolved.kind(Interner) { // I don't think we can ever unify these vars with float vars, but keep this here for now @@ -665,7 +645,11 @@ impl<'a> InferenceTable<'a> { } /// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that. - pub(crate) fn unify<T: ChalkToNextSolver<'a, U>, U: Relate<DbInterner<'a>>>(&mut self, ty1: &T, ty2: &T) -> bool { + pub(crate) fn unify<T: ChalkToNextSolver<'a, U>, U: Relate<DbInterner<'a>>>( + &mut self, + ty1: &T, + ty2: &T, + ) -> bool { let result = match self.try_unify(ty1, ty2) { Ok(r) => r, Err(_) => return false, @@ -675,17 +659,17 @@ impl<'a> InferenceTable<'a> { } /// Unify two relatable values (e.g. `Ty`) and check whether trait goals which arise from that could be fulfilled - pub(crate) fn unify_deeply<T: ChalkToNextSolver<'a, U>, U: Relate<DbInterner<'a>>>(&mut self, ty1: &T, ty2: &T) -> bool { + pub(crate) fn unify_deeply<T: ChalkToNextSolver<'a, U>, U: Relate<DbInterner<'a>>>( + &mut self, + ty1: &T, + ty2: &T, + ) -> bool { let result = match self.try_unify(ty1, ty2) { Ok(r) => r, Err(_) => return false, }; - result.goals.iter().all(|goal| { - let goal = goal.to_nextsolver(self.interner); - match next_trait_solve_in_ctxt(&self.infer_ctxt, goal) { - Ok((_, Certainty::Yes)) => true, - _ => false, - } + result.goals.into_iter().all(|goal| { + matches!(next_trait_solve_in_ctxt(&self.infer_ctxt, goal), Ok((_, Certainty::Yes))) }) } @@ -695,20 +679,15 @@ impl<'a> InferenceTable<'a> { &mut self, t1: &T, t2: &T, - ) -> InferResult<()> { + ) -> InferResult<'a, ()> { let param_env = self.trait_env.env.to_nextsolver(self.interner); let lhs = t1.to_nextsolver(self.interner); let rhs = t2.to_nextsolver(self.interner); let variance = rustc_type_ir::Variance::Invariant; let span = crate::next_solver::Span::dummy(); match self.infer_ctxt.relate(param_env, lhs, variance, rhs, span) { - Ok(res) => { - let goals = res.into_iter().map(|g| ChalkToNextSolver::from_nextsolver(g, self.interner)).collect(); - Ok(InferOk { goals, value: () }) - } - Err(_) => { - Err(TypeError) - } + Ok(goals) => Ok(InferOk { goals, value: () }), + Err(_) => Err(TypeError), } } @@ -719,19 +698,75 @@ impl<'a> InferenceTable<'a> { if !ty.data(Interner).flags.intersects(chalk_ir::TypeFlags::HAS_FREE_LOCAL_NAMES) { return ty.clone(); } + self.infer_ctxt + .resolve_vars_if_possible(ty.to_nextsolver(self.interner)) + .to_chalk(self.interner) + } + + pub(crate) fn resolve_vars_with_obligations<T>(&mut self, t: T) -> T + where + T: rustc_type_ir::TypeFoldable<DbInterner<'a>>, + { + use rustc_type_ir::TypeVisitableExt; + + if !t.has_non_region_infer() { + return t; + } + + let t = self.infer_ctxt.resolve_vars_if_possible(t); + + if !t.has_non_region_infer() { + return t; + } + + self.resolve_obligations_as_possible(); + self.infer_ctxt.resolve_vars_if_possible(t) + } + + pub(crate) fn structurally_resolve_type(&mut self, ty: &Ty) -> Ty { + if let TyKind::Alias(..) = ty.kind(Interner) { + self.structurally_normalize_ty(ty) + } else { + self.resolve_vars_with_obligations(ty.to_nextsolver(self.interner)) + .to_chalk(self.interner) + } + } + + fn structurally_normalize_ty(&mut self, ty: &Ty) -> Ty { + self.structurally_normalize_term(ty.to_nextsolver(self.interner).into()) + .expect_ty() + .to_chalk(self.interner) + } + + fn structurally_normalize_term(&mut self, term: Term<'a>) -> Term<'a> { + if term.to_alias_term().is_none() { + return term; + } + + let new_infer = self.infer_ctxt.next_term_var_of_kind(term); + + self.register_obligation(Predicate::new( + self.interner, + Binder::dummy(PredicateKind::AliasRelate( + term, + new_infer, + AliasRelationDirection::Equate, + )), + )); self.resolve_obligations_as_possible(); - ChalkToNextSolver::from_nextsolver(self.infer_ctxt.resolve_vars_if_possible(ty.to_nextsolver(self.interner)), self.interner) + let res = self.infer_ctxt.resolve_vars_if_possible(new_infer); + if res == new_infer { term } else { res } } - pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot { + pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot<'a> { let ctxt_snapshot = self.infer_ctxt.start_snapshot(); let diverging_tys = self.diverging_tys.clone(); let pending_obligations = self.pending_obligations.clone(); - InferenceTableSnapshot {ctxt_snapshot, pending_obligations, diverging_tys } + InferenceTableSnapshot { ctxt_snapshot, pending_obligations, diverging_tys } } #[tracing::instrument(skip_all)] - pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot) { + pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot<'a>) { self.infer_ctxt.rollback_to(snapshot.ctxt_snapshot); self.diverging_tys = snapshot.diverging_tys; self.pending_obligations = snapshot.pending_obligations; @@ -745,7 +780,10 @@ impl<'a> InferenceTable<'a> { result } - pub(crate) fn commit_if_ok<T, E>(&mut self, f: impl FnOnce(&mut InferenceTable<'_>) -> Result<T, E>) -> Result<T, E> { + pub(crate) fn commit_if_ok<T, E>( + &mut self, + f: impl FnOnce(&mut InferenceTable<'_>) -> Result<T, E>, + ) -> Result<T, E> { let snapshot = self.snapshot(); let result = f(self); match result { @@ -765,59 +803,31 @@ impl<'a> InferenceTable<'a> { let in_env = InEnvironment::new(&self.trait_env.env, goal); let canonicalized = self.canonicalize(in_env.to_nextsolver(self.interner)); - next_trait_solve_canonical(self.db, self.trait_env.krate, self.trait_env.block, canonicalized) + next_trait_solve_canonical_in_ctxt(&self.infer_ctxt, canonicalized) } - + #[tracing::instrument(level = "debug", skip(self))] pub(crate) fn solve_obligation(&mut self, goal: Goal) -> Result<Certainty, NoSolution> { let goal = InEnvironment::new(&self.trait_env.env, goal); - let Some(goal) = self.unify_opaque_instead_of_solve(goal) else { - return Ok(Certainty::Yes); - }; - let goal = goal.to_nextsolver(self.interner); let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal); result.map(|m| m.1) } - pub(crate) fn register_obligation(&mut self, goal: Goal) { - let in_env = InEnvironment::new(&self.trait_env.env, goal); - self.register_obligation_in_env(in_env) - } - - // If this goal is an `AliasEq` for an opaque type, just unify instead of trying to solve (since the next-solver is lazy) - fn unify_opaque_instead_of_solve(&mut self, goal: InEnvironment<Goal>) -> Option<InEnvironment<Goal>> { - match goal.goal.data(Interner) { - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }), - )) => { - if ty.inference_var(Interner).is_some() { - match alias { - chalk_ir::AliasTy::Opaque(opaque) => { - if self.unify( - &chalk_ir::TyKind::OpaqueType( - opaque.opaque_ty_id, - opaque.substitution.clone(), - ) - .intern(Interner), - ty, - ) { - return None; - } - } - _ => {} - } - } - } - _ => {} - } - Some(goal) + pub(crate) fn register_obligation(&mut self, predicate: Predicate<'a>) { + let goal = next_solver::Goal { + param_env: self.trait_env.env.to_nextsolver(self.interner), + predicate, + }; + self.register_obligation_in_env(goal) } #[tracing::instrument(level = "debug", skip(self))] - fn register_obligation_in_env(&mut self, goal: InEnvironment<Goal>) { - let Some(goal) = self.unify_opaque_instead_of_solve(goal) else { return }; - let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal.to_nextsolver(self.interner)); + fn register_obligation_in_env( + &mut self, + goal: next_solver::Goal<'a, next_solver::Predicate<'a>>, + ) { + let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal); tracing::debug!(?result); match result { Ok((_, Certainty::Yes)) => {} @@ -828,7 +838,7 @@ impl<'a> InferenceTable<'a> { } } - pub(crate) fn register_infer_ok<T>(&mut self, infer_ok: InferOk<T>) { + pub(crate) fn register_infer_ok<T>(&mut self, infer_ok: InferOk<'a, T>) { infer_ok.goals.into_iter().for_each(|goal| self.register_obligation_in_env(goal)); } @@ -841,12 +851,7 @@ impl<'a> InferenceTable<'a> { for goal in obligations.drain(..) { tracing::debug!(obligation = ?goal); - let Some(goal) = self.unify_opaque_instead_of_solve(goal) else { - changed = true; - continue; - }; - - let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal.to_nextsolver(self.interner)); + let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal); let (has_changed, certainty) = match result { Ok(result) => result, Err(_) => { @@ -934,40 +939,6 @@ impl<'a> InferenceTable<'a> { .fold_with(&mut VarFudger { table: self, highest_known_var }, DebruijnIndex::INNERMOST) } - #[tracing::instrument(level = "debug", skip(self))] - fn try_resolve_obligation( - &mut self, - canonicalized: &Canonicalized<InEnvironment<Goal>>, - ) -> NextTraitSolveResult { - let solution = next_trait_solve( - self.db, - self.trait_env.krate, - self.trait_env.block, - canonicalized.value.clone(), - ); - - tracing::debug!(?solution, ?canonicalized); - match &solution { - NextTraitSolveResult::Certain(v) => { - canonicalized.apply_solution( - self, - Canonical { - binders: v.binders.clone(), - // FIXME handle constraints - value: v.value.subst.clone(), - }, - ); - } - // ...so, should think about how to get some actually get some guidance here - NextTraitSolveResult::Uncertain(v) => { - canonicalized.apply_solution(self, v.clone()); - } - NextTraitSolveResult::NoSolution => {} - } - - solution - } - pub(crate) fn callable_sig( &mut self, ty: &Ty, @@ -1027,7 +998,7 @@ impl<'a> InferenceTable<'a> { let goal: Goal = trait_ref.clone().cast(Interner); if !self.try_obligation(goal.clone()).no_solution() { - self.register_obligation(goal); + self.register_obligation(goal.to_nextsolver(self.interner)); let return_ty = self.normalize_projection_ty(projection); for &fn_x in subtraits { let fn_x_trait = fn_x.get_id(self.db, krate)?; @@ -1067,7 +1038,7 @@ impl<'a> InferenceTable<'a> { match ty.kind(Interner) { TyKind::Error => self.new_type_var(), TyKind::InferenceVar(..) => { - let ty_resolved = self.resolve_ty_shallow(&ty); + let ty_resolved = self.structurally_resolve_type(&ty); if ty_resolved.is_unknown() { self.new_type_var() } else { ty } } _ => ty, @@ -1165,7 +1136,9 @@ impl fmt::Debug for InferenceTable<'_> { mod resolve { use super::InferenceTable; use crate::{ - next_solver::mapping::ChalkToNextSolver, ConcreteConst, Const, ConstData, ConstScalar, ConstValue, DebruijnIndex, GenericArg, InferenceVar, Interner, Lifetime, Ty, TyVariableKind, VariableKind + ConcreteConst, Const, ConstData, ConstScalar, ConstValue, DebruijnIndex, GenericArg, + InferenceVar, Interner, Lifetime, Ty, TyVariableKind, VariableKind, + next_solver::mapping::NextSolverToChalk, }; use chalk_ir::{ cast::Cast, @@ -1220,7 +1193,7 @@ mod resolve { .clone(); } if let Ok(known_ty) = self.table.infer_ctxt.probe_ty_var(vid) { - let known_ty: Ty = ChalkToNextSolver::from_nextsolver(known_ty, self.table.interner); + let known_ty: Ty = known_ty.to_chalk(self.table.interner); // known_ty may contain other variables that are known by now self.var_stack.push((var, VarKind::Ty(kind))); let result = known_ty.fold_with(self, outer_binder); @@ -1234,7 +1207,13 @@ mod resolve { } } TyVariableKind::Integer => { - let vid = self.table.infer_ctxt.inner.borrow_mut().int_unification_table().find(IntVid::from(var.index())); + let vid = self + .table + .infer_ctxt + .inner + .borrow_mut() + .int_unification_table() + .find(IntVid::from(var.index())); let var = InferenceVar::from(vid.as_u32()); if self.var_stack.contains(&(var, VarKind::Ty(kind))) { // recursive type @@ -1244,7 +1223,7 @@ mod resolve { .clone(); } if let Some(known_ty) = self.table.infer_ctxt.resolve_int_var(vid) { - let known_ty: Ty = ChalkToNextSolver::from_nextsolver(known_ty, self.table.interner); + let known_ty: Ty = known_ty.to_chalk(self.table.interner); // known_ty may contain other variables that are known by now self.var_stack.push((var, VarKind::Ty(kind))); let result = known_ty.fold_with(self, outer_binder); @@ -1258,7 +1237,13 @@ mod resolve { } } TyVariableKind::Float => { - let vid = self.table.infer_ctxt.inner.borrow_mut().float_unification_table().find(FloatVid::from(var.index())); + let vid = self + .table + .infer_ctxt + .inner + .borrow_mut() + .float_unification_table() + .find(FloatVid::from(var.index())); let var = InferenceVar::from(vid.as_u32()); if self.var_stack.contains(&(var, VarKind::Ty(kind))) { // recursive type @@ -1268,7 +1253,7 @@ mod resolve { .clone(); } if let Some(known_ty) = self.table.infer_ctxt.resolve_float_var(vid) { - let known_ty: Ty = ChalkToNextSolver::from_nextsolver(known_ty, self.table.interner); + let known_ty: Ty = known_ty.to_chalk(self.table.interner); // known_ty may contain other variables that are known by now self.var_stack.push((var, VarKind::Ty(kind))); let result = known_ty.fold_with(self, outer_binder); @@ -1290,7 +1275,10 @@ mod resolve { var: InferenceVar, outer_binder: DebruijnIndex, ) -> Const { - let vid = self.table.infer_ctxt.root_const_var(rustc_type_ir::ConstVid::from_u32(var.index())); + let vid = self + .table + .infer_ctxt + .root_const_var(rustc_type_ir::ConstVid::from_u32(var.index())); let var = InferenceVar::from(vid.as_u32()); let default = ConstData { ty: ty.clone(), @@ -1305,7 +1293,7 @@ mod resolve { .clone(); } if let Ok(known_const) = self.table.infer_ctxt.probe_const_var(vid) { - let known_const: Const = ChalkToNextSolver::from_nextsolver(known_const, self.table.interner); + let known_const: Const = known_const.to_chalk(self.table.interner); // known_ty may contain other variables that are known by now self.var_stack.push((var, VarKind::Const)); let result = known_const.fold_with(self, outer_binder); |