Unnamed repository; edit this file 'description' to name the repository.
WIP switch inference table to next-solver
jackh726 8 months ago
parent 6da1ce7 · commit d24e8c1
-rw-r--r--crates/hir-ty/src/consteval_nextsolver.rs6
-rw-r--r--crates/hir-ty/src/infer/closure.rs2
-rw-r--r--crates/hir-ty/src/infer/coerce.rs64
-rw-r--r--crates/hir-ty/src/infer/expr.rs32
-rw-r--r--crates/hir-ty/src/infer/path.rs12
-rw-r--r--crates/hir-ty/src/infer/unify.rs589
-rw-r--r--crates/hir-ty/src/lib.rs16
-rw-r--r--crates/hir-ty/src/method_resolution.rs201
-rw-r--r--crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs785
-rw-r--r--crates/hir-ty/src/next_solver/infer/canonical/mod.rs1
-rw-r--r--crates/hir-ty/src/next_solver/infer/mod.rs54
-rw-r--r--crates/hir-ty/src/next_solver/infer/snapshot/mod.rs4
-rw-r--r--crates/hir-ty/src/next_solver/mapping.rs965
-rw-r--r--crates/hir-ty/src/next_solver/solver.rs4
-rw-r--r--crates/hir-ty/src/traits.rs67
-rw-r--r--crates/hir/src/attrs.rs4
-rw-r--r--crates/hir/src/lib.rs12
17 files changed, 2292 insertions, 526 deletions
diff --git a/crates/hir-ty/src/consteval_nextsolver.rs b/crates/hir-ty/src/consteval_nextsolver.rs
index 4f95c9a13a..4700335931 100644
--- a/crates/hir-ty/src/consteval_nextsolver.rs
+++ b/crates/hir-ty/src/consteval_nextsolver.rs
@@ -27,7 +27,7 @@ use crate::{
next_solver::{
Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs,
ParamConst, SolverDefId, Ty, ValueConst,
- mapping::{ChalkToNextSolver, convert_args_for_result, convert_binder_to_early_binder},
+ mapping::{ChalkToNextSolver, convert_binder_to_early_binder},
},
};
@@ -145,7 +145,7 @@ pub fn try_const_usize<'db>(db: &'db dyn HirDatabase, c: Const<'db>) -> Option<u
SolverDefId::StaticId(id) => GeneralConstId::StaticId(id),
_ => unreachable!(),
};
- let subst = convert_args_for_result(interner, unevaluated_const.args.as_slice());
+ let subst = ChalkToNextSolver::from_nextsolver(unevaluated_const.args, interner);
let ec = db.const_eval(c, subst, None).ok()?.to_nextsolver(interner);
try_const_usize(db, ec)
}
@@ -168,7 +168,7 @@ pub fn try_const_isize<'db>(db: &'db dyn HirDatabase, c: &Const<'db>) -> Option<
SolverDefId::StaticId(id) => GeneralConstId::StaticId(id),
_ => unreachable!(),
};
- let subst = convert_args_for_result(interner, unevaluated_const.args.as_slice());
+ let subst = ChalkToNextSolver::from_nextsolver(unevaluated_const.args, interner);
let ec = db.const_eval(c, subst, None).ok()?.to_nextsolver(interner);
try_const_isize(db, &ec)
}
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index 9ef046afdb..493652b764 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -568,7 +568,7 @@ impl InferenceContext<'_> {
let supplied_sig = self.supplied_sig_of_closure(body, ret_type, arg_types, closure_kind);
let snapshot = self.table.snapshot();
- if !self.table.unify(&expected_sig.substitution, &supplied_sig.expected_sig.substitution) {
+ if !self.table.unify::<_, crate::next_solver::GenericArgs<'_>>(&expected_sig.substitution.0, &supplied_sig.expected_sig.substitution.0) {
self.table.rollback_to(snapshot);
}
diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs
index 631a91bac4..b47834f0c7 100644
--- a/crates/hir-ty/src/infer/coerce.rs
+++ b/crates/hir-ty/src/infer/coerce.rs
@@ -7,22 +7,20 @@
use std::iter;
-use chalk_ir::{BoundVar, Goal, Mutability, TyKind, TyVariableKind, cast::Cast};
-use hir_def::{hir::ExprId, lang_item::LangItem};
+use chalk_ir::{BoundVar, Mutability, TyKind, TyVariableKind, cast::Cast};
+use hir_def::{
+ hir::ExprId,
+ lang_item::LangItem,
+};
+use rustc_type_ir::solve::Certainty;
use stdx::always;
use triomphe::Arc;
use crate::{
- Canonical, DomainGoal, FnAbi, FnPointer, FnSig, InEnvironment, Interner, Lifetime,
- Substitution, TraitEnvironment, Ty, TyBuilder, TyExt,
- autoderef::{Autoderef, AutoderefKind},
- db::HirDatabase,
- infer::{
+ autoderef::{Autoderef, AutoderefKind}, db::HirDatabase, infer::{
Adjust, Adjustment, AutoBorrow, InferOk, InferenceContext, OverloadedDeref, PointerCast,
TypeError, TypeMismatch,
- },
- traits::NextTraitSolveResult,
- utils::ClosureSubst,
+ }, utils::ClosureSubst, Canonical, FnAbi, FnPointer, FnSig, Goal, InEnvironment, Interner, Lifetime, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt
};
use super::unify::InferenceTable;
@@ -42,7 +40,7 @@ fn simple(kind: Adjust) -> impl FnOnce(Ty) -> Vec<Adjustment> {
fn success(
adj: Vec<Adjustment>,
target: Ty,
- goals: Vec<InEnvironment<Goal<Interner>>>,
+ goals: Vec<InEnvironment<Goal>>,
) -> CoerceResult {
Ok(InferOk { goals, value: (adj, target) })
}
@@ -304,7 +302,7 @@ impl InferenceTable<'_> {
fn coerce_inner(&mut self, from_ty: Ty, to_ty: &Ty, coerce_never: CoerceNever) -> CoerceResult {
if from_ty.is_never() {
if let TyKind::InferenceVar(tv, TyVariableKind::General) = to_ty.kind(Interner) {
- self.set_diverging(*tv, true);
+ self.set_diverging(*tv, TyVariableKind::General, true);
}
if coerce_never == CoerceNever::Yes {
// Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound
@@ -707,41 +705,15 @@ impl InferenceTable<'_> {
b.push(coerce_from).push(to_ty.clone()).build()
};
- let goal: InEnvironment<DomainGoal> =
- InEnvironment::new(&self.trait_env.env, coerce_unsized_tref.cast(Interner));
-
- let canonicalized = self.canonicalize_with_free_vars(goal);
-
- // FIXME: rustc's coerce_unsized is more specialized -- it only tries to
- // solve `CoerceUnsized` and `Unsize` goals at this point and leaves the
- // rest for later. Also, there's some logic about sized type variables.
- // Need to find out in what cases this is necessary
- let solution = self.db.trait_solve(
- krate,
- self.trait_env.block,
- canonicalized.value.clone().cast(Interner),
- );
-
- match solution {
- // FIXME: this is a weaker guarantee than Chalk's `Guidance::Unique`
- // was. Chalk's unique guidance at least guarantees that the real solution
- // is some "subset" of the solutions matching the guidance, but the
- // substs for `Certainty::No` don't have that same guarantee (I think).
- NextTraitSolveResult::Certain(v) => {
- canonicalized.apply_solution(
- self,
- Canonical {
- binders: v.binders,
- // FIXME handle constraints
- value: v.value.subst,
- },
- );
- }
- // ...so, should think about how to get some actually get some guidance here
- NextTraitSolveResult::Uncertain(..) | NextTraitSolveResult::NoSolution => {
- return Err(TypeError);
+ let goal: Goal = coerce_unsized_tref.cast(Interner);
+
+ self.commit_if_ok(|table| {
+ match table.solve_obligation(goal) {
+ Ok(Certainty::Yes) => Ok(()),
+ Ok(Certainty::Maybe(_)) => Ok(()),
+ Err(_) => Err(TypeError),
}
- }
+ })?;
let unsize =
Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target: to_ty.clone() };
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 261c023868..e39f3ab75f 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -23,28 +23,9 @@ use stdx::always;
use syntax::ast::RangeOp;
use crate::{
- Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, CallableSig, DeclContext,
- DeclOrigin, IncorrectGenericsLenKind, Interner, Rawness, Scalar, Substitution,
- TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
- autoderef::{Autoderef, builtin_deref, deref_by_trait},
- consteval,
- generics::generics,
- infer::{
- BreakableKind,
- coerce::{CoerceMany, CoerceNever, CoercionCause},
- find_continuable,
- pat::contains_explicit_ref_binding,
- },
- lang_items::lang_items_for_bin_op,
- lower::{
- LifetimeElisionKind, ParamLoweringMode, lower_to_chalk_mutability,
- path::{GenericArgsLowerer, TypeLikeConst, substs_from_args_and_bindings},
- },
- mapping::{ToChalk, from_chalk},
- method_resolution::{self, VisibleFromModule},
- primitive::{self, UintTy},
- static_lifetime, to_chalk_trait_id,
- traits::FnTrait,
+ autoderef::{builtin_deref, deref_by_trait, Autoderef}, consteval, generics::generics, infer::{
+ coerce::{CoerceMany, CoerceNever, CoercionCause}, find_continuable, pat::contains_explicit_ref_binding, BreakableKind
+ }, lang_items::lang_items_for_bin_op, lower::{lower_to_chalk_mutability, path::{substs_from_args_and_bindings, GenericArgsLowerer, TypeLikeConst}, ParamLoweringMode}, mapping::{from_chalk, ToChalk}, method_resolution::{self, VisibleFromModule}, next_solver::mapping::ChalkToNextSolver, primitive::{self, UintTy}, static_lifetime, to_chalk_trait_id, traits::FnTrait, Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, CallableSig, DeclContext, DeclOrigin, IncorrectGenericsLenKind, Interner, LifetimeElisionKind, Rawness, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind
};
use super::{
@@ -826,7 +807,7 @@ impl InferenceContext<'_> {
let index_ty = self.infer_expr(*index, &Expectation::none(), ExprIsRead::Yes);
if let Some(index_trait) = self.resolve_lang_trait(LangItem::Index) {
- let canonicalized = self.canonicalize(base_ty.clone());
+ let canonicalized = ChalkToNextSolver::from_nextsolver(self.canonicalize(base_ty.clone().to_nextsolver(self.table.interner)), self.table.interner);
let receiver_adjustments = method_resolution::resolve_indexing_op(
self.db,
self.table.trait_env.clone(),
@@ -932,6 +913,7 @@ impl InferenceContext<'_> {
}
None => {
let expected_ty = expected.to_option(&mut self.table);
+ tracing::debug!(?expected_ty);
let opt_ty = match expected_ty.as_ref().map(|it| it.kind(Interner)) {
Some(TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))) => expected_ty,
Some(TyKind::Scalar(Scalar::Char)) => {
@@ -1678,7 +1660,7 @@ impl InferenceContext<'_> {
None => {
// no field found, lets attempt to resolve it like a function so that IDE things
// work out while people are typing
- let canonicalized_receiver = self.canonicalize(receiver_ty.clone());
+ let canonicalized_receiver = self.canonicalize(receiver_ty.clone().to_nextsolver(self.table.interner));
let resolved = method_resolution::lookup_method(
self.db,
&canonicalized_receiver,
@@ -1824,7 +1806,7 @@ impl InferenceContext<'_> {
expected: &Expectation,
) -> Ty {
let receiver_ty = self.infer_expr_inner(receiver, &Expectation::none(), ExprIsRead::Yes);
- let canonicalized_receiver = self.canonicalize(receiver_ty.clone());
+ let canonicalized_receiver = self.canonicalize(receiver_ty.clone().to_nextsolver(self.table.interner));
let resolved = method_resolution::lookup_method(
self.db,
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index bc8648ecdd..9f3cd2b8fb 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -10,15 +10,7 @@ use hir_expand::name::Name;
use stdx::never;
use crate::{
- InferenceDiagnostic, Interner, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt,
- TyKind, ValueTyDefId,
- builder::ParamKind,
- consteval, error_lifetime,
- generics::generics,
- infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext,
- lower::LifetimeElisionKind,
- method_resolution::{self, VisibleFromModule},
- to_chalk_trait_id,
+ builder::ParamKind, consteval, error_lifetime, generics::generics, infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext, method_resolution::{self, VisibleFromModule}, next_solver::mapping::ChalkToNextSolver, to_chalk_trait_id, InferenceDiagnostic, Interner, LifetimeElisionKind, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId
};
use super::{ExprOrPatId, InferenceContext, InferenceTyDiagnosticSource};
@@ -322,7 +314,7 @@ impl InferenceContext<'_> {
return Some(result);
}
- let canonical_ty = self.canonicalize(ty.clone());
+ let canonical_ty = self.canonicalize(ty.clone().to_nextsolver(self.table.interner));
let mut not_visible = None;
let res = method_resolution::iterate_method_candidates(
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index bb4782bd41..3745d2c98f 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -3,35 +3,27 @@
use std::{fmt, mem};
use chalk_ir::{
- CanonicalVarKind, FloatTy, IntTy, TyVariableKind, UniverseIndex, cast::Cast,
- fold::TypeFoldable, interner::HasInterner, zip::Zip,
+ cast::Cast, fold::TypeFoldable, interner::HasInterner, CanonicalVarKind, FloatTy, IntTy, TyVariableKind,
};
-use chalk_solve::infer::ParameterEnaVariableExt;
use either::Either;
-use ena::unify::UnifyKey;
use hir_def::{AdtId, lang_item::LangItem};
use hir_expand::name::Name;
use intern::sym;
-use rustc_hash::FxHashMap;
+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 smallvec::SmallVec;
use triomphe::Arc;
use super::{InferOk, InferResult, InferenceContext, TypeError};
use crate::{
- 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, to_chalk_trait_id,
- traits::{FnTrait, NextTraitSolveResult},
+ 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
};
-impl InferenceContext<'_> {
- pub(super) fn canonicalize<T>(&mut self, t: T) -> Canonical<T>
+impl<'db> InferenceContext<'db> {
+ pub(super) fn canonicalize<T>(&mut self, t: T) -> rustc_type_ir::Canonical<DbInterner<'db>, T>
where
- T: TypeFoldable<Interner> + HasInterner<Interner = Interner>,
+ T: rustc_type_ir::TypeFoldable<DbInterner<'db>>,
{
self.table.canonicalize(t)
}
@@ -42,11 +34,11 @@ impl InferenceContext<'_> {
) -> SmallVec<[WhereClause; 4]> {
self.table.resolve_obligations_as_possible();
- let root = self.table.var_unification_table.inference_var_root(self_ty);
+ let root = InferenceVar::from_vid(self.table.infer_ctxt.root_var(self_ty.to_vid()));
let pending_obligations = mem::take(&mut self.table.pending_obligations);
let obligations = pending_obligations
.iter()
- .filter_map(|obligation| match obligation.value.value.goal.data(Interner) {
+ .filter_map(|obligation| match obligation.goal.data(Interner) {
GoalData::DomainGoal(DomainGoal::Holds(clause)) => {
let ty = match clause {
WhereClause::AliasEq(AliasEq {
@@ -59,18 +51,9 @@ impl InferenceContext<'_> {
WhereClause::TypeOutlives(to) => to.ty.clone(),
_ => return None,
};
-
- let uncanonical =
- chalk_ir::Substitute::apply(&obligation.free_vars, ty, Interner);
- if matches!(
- self.resolve_ty_shallow(&uncanonical).kind(Interner),
- TyKind::InferenceVar(iv, TyVariableKind::General) if *iv == root,
- ) {
- Some(chalk_ir::Substitute::apply(
- &obligation.free_vars,
- clause.clone(),
- Interner,
- ))
+ let ty = self.resolve_ty_shallow(&ty);
+ if matches!(ty.kind(Interner), TyKind::InferenceVar(iv, TyVariableKind::General) if *iv == root) {
+ Some(clause.clone())
} else {
None
}
@@ -229,32 +212,31 @@ 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>>,
- var_unification_table: ChalkInferenceTable,
- type_variable_table: SmallVec<[TypeVariableFlags; 16]>,
- pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
- /// Double buffer used in [`Self::resolve_obligations_as_possible`] to cut down on
- /// temporary allocations.
- resolve_obligations_buffer: Vec<Canonicalized<InEnvironment<Goal>>>,
+ infer_ctxt: InferCtxt<'a>,
+ diverging_tys: FxHashSet<Ty>,
+ pending_obligations: Vec<InEnvironment<Goal>>,
}
pub(crate) struct InferenceTableSnapshot {
- var_table_snapshot: chalk_solve::infer::InferenceSnapshot<Interner>,
- type_variable_table: SmallVec<[TypeVariableFlags; 16]>,
- pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
+ ctxt_snapshot: CombinedSnapshot,
+ diverging_tys: FxHashSet<Ty>,
+ pending_obligations: Vec<InEnvironment<Goal>>,
}
impl<'a> InferenceTable<'a> {
pub(crate) fn new(db: &'a dyn HirDatabase, trait_env: Arc<TraitEnvironment>) -> Self {
+ let interner = DbInterner::new_with(db, Some(trait_env.krate), trait_env.block);
InferenceTable {
db,
+ interner,
trait_env,
tait_coercion_table: None,
- var_unification_table: ChalkInferenceTable::new(),
- type_variable_table: SmallVec::new(),
+ 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(),
- resolve_obligations_buffer: Vec::new(),
}
}
@@ -265,29 +247,43 @@ impl<'a> InferenceTable<'a> {
/// marked as diverging if necessary, so that resolving them gives the right
/// result.
pub(super) fn propagate_diverging_flag(&mut self) {
- for i in 0..self.type_variable_table.len() {
- if !self.type_variable_table[i].contains(TypeVariableFlags::DIVERGING) {
- continue;
+ 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));
+ }
+ }
+ 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));
+ }
+ }
+ }
+ }
+ _ => {}
}
- let v = InferenceVar::from(i as u32);
- let root = self.var_unification_table.inference_var_root(v);
- self.modify_type_variable_flag(root, |f| {
- *f |= TypeVariableFlags::DIVERGING;
- });
}
+ self.diverging_tys.extend(new_tys.into_iter());
}
- pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) {
- self.modify_type_variable_flag(iv, |f| {
- f.set(TypeVariableFlags::DIVERGING, diverging);
- });
+ pub(super) fn set_diverging(&mut self, iv: InferenceVar, kind: TyVariableKind, diverging: bool) {
+ self.diverging_tys.insert(TyKind::InferenceVar(iv, kind).intern(Interner));
}
fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty {
- let is_diverging = self
- .type_variable_table
- .get(iv.index() as usize)
- .is_some_and(|data| data.contains(TypeVariableFlags::DIVERGING));
+ let is_diverging = self.diverging_tys.contains(&TyKind::InferenceVar(iv, kind).intern(Interner));
if is_diverging {
return TyKind::Never.intern(Interner);
}
@@ -299,30 +295,27 @@ impl<'a> InferenceTable<'a> {
.intern(Interner)
}
- pub(crate) fn canonicalize_with_free_vars<T>(&mut self, t: T) -> Canonicalized<T>
+ 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: TypeFoldable<Interner> + HasInterner<Interner = Interner>,
+ 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 result = self.var_unification_table.canonicalize(Interner, t);
- let free_vars = result
- .free_vars
- .into_iter()
- .map(|free_var| free_var.to_generic_arg(Interner))
- .collect();
- Canonicalized { value: result.quantified, free_vars }
+
+ 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) -> Canonical<T>
+ pub(crate) fn canonicalize<T>(&mut self, t: T) -> rustc_type_ir::Canonical<DbInterner<'a>, T>
where
- T: TypeFoldable<Interner> + HasInterner<Interner = Interner>,
+ 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();
- self.var_unification_table.canonicalize(Interner, t).quantified
+ self.infer_ctxt.canonicalize_response(t)
}
/// Recurses through the given type, normalizing associated types mentioned
@@ -348,6 +341,7 @@ impl<'a> InferenceTable<'a> {
self.resolve_ty_shallow(&ty)
}
TyKind::AssociatedType(id, subst) => {
+ 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,
@@ -370,21 +364,24 @@ 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 canonicalized = {
- let result =
- self.var_unification_table.canonicalize(Interner, in_env);
- let free_vars = result
- .free_vars
- .into_iter()
- .map(|free_var| free_var.to_generic_arg(Interner))
- .collect();
- Canonicalized { value: result.quantified, free_vars }
+ let (canonical_goal, _orig_values) = {
+ let mut orig_values = OriginalQueryValues::default();
+ 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 },
};
- let solution = self.db.trait_solve(
+ let solution = next_trait_solve_canonical(
+ self.db,
self.trait_env.krate,
self.trait_env.block,
- canonicalized.value.clone(),
+ canonical_goal.clone(),
);
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.
@@ -512,38 +509,27 @@ impl<'a> InferenceTable<'a> {
var
}
- fn modify_type_variable_flag<F>(&mut self, var: InferenceVar, cb: F)
- where
- F: FnOnce(&mut TypeVariableFlags),
- {
- let idx = var.index() as usize;
- if self.type_variable_table.len() <= idx {
- self.extend_type_variable_table(idx);
- }
- if let Some(f) = self.type_variable_table.get_mut(idx) {
- cb(f);
- }
- }
- fn extend_type_variable_table(&mut self, to_index: usize) {
- let count = to_index - self.type_variable_table.len() + 1;
- self.type_variable_table.extend(std::iter::repeat_n(TypeVariableFlags::default(), count));
- }
-
fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty {
- let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
- // Chalk might have created some type variables for its own purposes that we don't know about...
- self.extend_type_variable_table(var.index() as usize);
- assert_eq!(var.index() as usize, self.type_variable_table.len() - 1);
- let flags = self.type_variable_table.get_mut(var.index() as usize).unwrap();
+ let var = match kind {
+ TyVariableKind::General => {
+ let var = self.infer_ctxt.next_ty_vid();
+ InferenceVar::from(var.as_u32())
+ }
+ TyVariableKind::Integer => {
+ let var = self.infer_ctxt.next_int_vid();
+ InferenceVar::from(var.as_u32())
+ }
+ TyVariableKind::Float => {
+ let var = self.infer_ctxt.next_float_vid();
+ InferenceVar::from(var.as_u32())
+ }
+ };
+
+ let ty = var.to_ty(Interner, kind);
if diverging {
- *flags |= TypeVariableFlags::DIVERGING;
- }
- if matches!(kind, TyVariableKind::Integer) {
- *flags |= TypeVariableFlags::INTEGER;
- } else if matches!(kind, TyVariableKind::Float) {
- *flags |= TypeVariableFlags::FLOAT;
+ self.diverging_tys.insert(ty.clone());
}
- var.to_ty_with_kind(Interner, kind)
+ ty
}
pub(crate) fn new_type_var(&mut self) -> Ty {
@@ -563,12 +549,14 @@ impl<'a> InferenceTable<'a> {
}
pub(crate) fn new_const_var(&mut self, ty: Ty) -> Const {
- let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
+ let var = self.infer_ctxt.next_const_vid();
+ let var = InferenceVar::from(var.as_u32());
var.to_const(Interner, ty)
}
pub(crate) fn new_lifetime_var(&mut self) -> Lifetime {
- let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
+ let var = self.infer_ctxt.next_region_vid();
+ let var = InferenceVar::from(var.as_u32());
var.to_lifetime(Interner)
}
@@ -580,16 +568,16 @@ impl<'a> InferenceTable<'a> {
where
T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
{
- self.resolve_with_fallback_inner(&mut Vec::new(), t, &fallback)
+ self.resolve_with_fallback_inner(t, &fallback)
}
pub(crate) fn fresh_subst(&mut self, binders: &[CanonicalVarKind<Interner>]) -> Substitution {
Substitution::from_iter(
Interner,
- binders.iter().map(|kind| {
- let param_infer_var =
- kind.map_ref(|&ui| self.var_unification_table.new_variable(ui));
- param_infer_var.to_generic_arg(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::Lifetime => self.new_lifetime_var().cast(Interner),
+ chalk_ir::VariableKind::Const(ty) => self.new_const_var(ty.clone()).cast(Interner),
}),
)
}
@@ -601,16 +589,23 @@ 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
+ where
+ T: rustc_type_ir::TypeFoldable<DbInterner<'a>>,
+ {
+ self.infer_ctxt.instantiate_canonical(&canonical).0
+ }
fn resolve_with_fallback_inner<T>(
&mut self,
- var_stack: &mut Vec<InferenceVar>,
t: T,
fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
) -> T
where
T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
{
+ let mut var_stack = &mut vec![];
t.fold_with(
&mut resolve::Resolver { table: self, var_stack, fallback },
DebruijnIndex::INNERMOST,
@@ -639,29 +634,26 @@ impl<'a> InferenceTable<'a> {
let int_fallback = TyKind::Scalar(Scalar::Int(IntTy::I32)).intern(Interner);
let float_fallback = TyKind::Scalar(Scalar::Float(FloatTy::F64)).intern(Interner);
- let scalar_vars: Vec<_> = self
- .type_variable_table
- .iter()
- .enumerate()
- .filter_map(|(index, flags)| {
- let kind = if flags.contains(TypeVariableFlags::INTEGER) {
- TyVariableKind::Integer
- } else if flags.contains(TypeVariableFlags::FLOAT) {
- TyVariableKind::Float
- } else {
- return None;
+ let int_vars = self.infer_ctxt.inner.borrow_mut().int_unification_table().len();
+ for v in 0..int_vars {
+ let var = InferenceVar::from(v as u32).to_ty(Interner, TyVariableKind::Integer);
+ 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
+ let fallback = match kind {
+ TyVariableKind::Integer => &int_fallback,
+ TyVariableKind::Float => &float_fallback,
+ TyVariableKind::General => unreachable!(),
};
-
- // FIXME: This is not really the nicest way to get `InferenceVar`s. Can we get them
- // without directly constructing them from `index`?
- let var = InferenceVar::from(index as u32).to_ty(Interner, kind);
- Some(var)
- })
- .collect();
-
- for var in scalar_vars {
+ self.unify(&var, fallback);
+ }
+ }
+ 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 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
let fallback = match kind {
TyVariableKind::Integer => &int_fallback,
TyVariableKind::Float => &float_fallback,
@@ -673,7 +665,7 @@ 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: ?Sized + Zip<Interner>>(&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,
@@ -683,58 +675,65 @@ 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: ?Sized + Zip<Interner>>(&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 canonicalized = self.canonicalize_with_free_vars(goal.clone());
- self.try_resolve_obligation(&canonicalized).certain()
+ let goal = goal.to_nextsolver(self.interner);
+ match next_trait_solve_in_ctxt(&self.infer_ctxt, goal) {
+ Ok((_, Certainty::Yes)) => true,
+ _ => false,
+ }
})
}
/// 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: ?Sized + Zip<Interner>>(
+ pub(crate) fn try_unify<T: ChalkToNextSolver<'a, U>, U: Relate<DbInterner<'a>>>(
&mut self,
t1: &T,
t2: &T,
) -> InferResult<()> {
- match self.var_unification_table.relate(
- Interner,
- &self.db,
- &self.trait_env.env,
- chalk_ir::Variance::Invariant,
- t1,
- t2,
- ) {
- Ok(result) => Ok(InferOk { goals: result.goals, value: () }),
- Err(chalk_ir::NoSolution) => Err(TypeError),
+ 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)
+ }
}
}
/// If `ty` is a type variable with known type, returns that type;
/// otherwise, return ty.
+ #[tracing::instrument(skip(self))]
pub(crate) fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty {
if !ty.data(Interner).flags.intersects(chalk_ir::TypeFlags::HAS_FREE_LOCAL_NAMES) {
return ty.clone();
}
self.resolve_obligations_as_possible();
- self.var_unification_table.normalize_ty_shallow(Interner, ty).unwrap_or_else(|| ty.clone())
+ ChalkToNextSolver::from_nextsolver(self.infer_ctxt.resolve_vars_if_possible(ty.to_nextsolver(self.interner)), self.interner)
}
pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot {
- let var_table_snapshot = self.var_unification_table.snapshot();
- let type_variable_table = self.type_variable_table.clone();
+ let ctxt_snapshot = self.infer_ctxt.start_snapshot();
+ let diverging_tys = self.diverging_tys.clone();
let pending_obligations = self.pending_obligations.clone();
- InferenceTableSnapshot { var_table_snapshot, pending_obligations, type_variable_table }
+ InferenceTableSnapshot {ctxt_snapshot, pending_obligations, diverging_tys }
}
#[tracing::instrument(skip_all)]
pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot) {
- self.var_unification_table.rollback_to(snapshot.var_table_snapshot);
- self.type_variable_table = snapshot.type_variable_table;
+ self.infer_ctxt.rollback_to(snapshot.ctxt_snapshot);
+ self.diverging_tys = snapshot.diverging_tys;
self.pending_obligations = snapshot.pending_obligations;
}
@@ -746,15 +745,39 @@ 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> {
+ let snapshot = self.snapshot();
+ let result = f(self);
+ match result {
+ Ok(_) => {}
+ 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, goal: Goal) -> NextTraitSolveResult {
let in_env = InEnvironment::new(&self.trait_env.env, goal);
- let canonicalized = self.canonicalize(in_env);
+ let canonicalized = self.canonicalize(in_env.to_nextsolver(self.interner));
- self.db.trait_solve(self.trait_env.krate, self.trait_env.block, canonicalized)
+ next_trait_solve_canonical(self.db, self.trait_env.krate, self.trait_env.block, 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) {
@@ -762,8 +785,8 @@ impl<'a> InferenceTable<'a> {
self.register_obligation_in_env(in_env)
}
- #[tracing::instrument(level = "debug", skip(self))]
- fn register_obligation_in_env(&mut self, goal: InEnvironment<Goal>) {
+ // 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 }),
@@ -779,7 +802,7 @@ impl<'a> InferenceTable<'a> {
.intern(Interner),
ty,
) {
- return;
+ return None;
}
}
_ => {}
@@ -788,20 +811,20 @@ impl<'a> InferenceTable<'a> {
}
_ => {}
}
- let canonicalized = {
- let result = self.var_unification_table.canonicalize(Interner, goal);
- let free_vars = result
- .free_vars
- .into_iter()
- .map(|free_var| free_var.to_generic_arg(Interner))
- .collect();
- Canonicalized { value: result.quantified, free_vars }
- };
- tracing::debug!(?canonicalized);
- let solution = self.try_resolve_obligation(&canonicalized);
- tracing::debug!(?solution);
- if solution.uncertain() {
- self.pending_obligations.push(canonicalized);
+ Some(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));
+ tracing::debug!(?result);
+ match result {
+ Ok((_, Certainty::Yes)) => {}
+ Err(rustc_type_ir::solve::NoSolution) => {}
+ Ok((_, Certainty::Maybe(_))) => {
+ self.pending_obligations.push(goal);
+ }
}
}
@@ -812,28 +835,35 @@ impl<'a> InferenceTable<'a> {
pub(crate) fn resolve_obligations_as_possible(&mut self) {
let _span = tracing::info_span!("resolve_obligations_as_possible").entered();
let mut changed = true;
- let mut obligations = mem::take(&mut self.resolve_obligations_buffer);
while mem::take(&mut changed) {
- mem::swap(&mut self.pending_obligations, &mut obligations);
+ let mut obligations = mem::take(&mut self.pending_obligations);
- for canonicalized in obligations.drain(..) {
- tracing::debug!(obligation = ?canonicalized);
- if !self.check_changed(&canonicalized) {
- tracing::debug!("not changed");
- self.pending_obligations.push(canonicalized);
+ 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 (has_changed, certainty) = match result {
+ Ok(result) => result,
+ Err(_) => {
+ continue;
+ }
+ };
+
+ if matches!(has_changed, HasChanged::Yes) {
+ changed = true;
+ }
+
+ match certainty {
+ Certainty::Yes => {}
+ Certainty::Maybe(_) => self.pending_obligations.push(goal),
}
- changed = true;
- let uncanonical = chalk_ir::Substitute::apply(
- &canonicalized.free_vars,
- canonicalized.value.value,
- Interner,
- );
- self.register_obligation_in_env(uncanonical);
}
}
- self.resolve_obligations_buffer = obligations;
- self.resolve_obligations_buffer.clear();
}
pub(crate) fn fudge_inference<T: TypeFoldable<Interner>>(
@@ -904,32 +934,13 @@ impl<'a> InferenceTable<'a> {
.fold_with(&mut VarFudger { table: self, highest_known_var }, DebruijnIndex::INNERMOST)
}
- /// This checks whether any of the free variables in the `canonicalized`
- /// have changed (either been unified with another variable, or with a
- /// value). If this is not the case, we don't need to try to solve the goal
- /// again -- it'll give the same result as last time.
- fn check_changed(&mut self, canonicalized: &Canonicalized<InEnvironment<Goal>>) -> bool {
- canonicalized.free_vars.iter().any(|var| {
- let iv = match var.data(Interner) {
- GenericArgData::Ty(ty) => ty.inference_var(Interner),
- GenericArgData::Lifetime(lt) => lt.inference_var(Interner),
- GenericArgData::Const(c) => c.inference_var(Interner),
- }
- .expect("free var is not inference var");
- if self.var_unification_table.probe_var(iv).is_some() {
- return true;
- }
- let root = self.var_unification_table.inference_var_root(iv);
- iv != root
- })
- }
-
#[tracing::instrument(level = "debug", skip(self))]
fn try_resolve_obligation(
&mut self,
canonicalized: &Canonicalized<InEnvironment<Goal>>,
) -> NextTraitSolveResult {
- let solution = self.db.trait_solve(
+ let solution = next_trait_solve(
+ self.db,
self.trait_env.krate,
self.trait_env.block,
canonicalized.value.clone(),
@@ -1014,33 +1025,15 @@ impl<'a> InferenceTable<'a> {
.fill_with_unknown()
.build();
- let trait_env = self.trait_env.env.clone();
- let obligation = InEnvironment {
- goal: trait_ref.clone().cast(Interner),
- environment: trait_env.clone(),
- };
- let canonical = self.canonicalize(obligation.clone());
- if !self
- .db
- .trait_solve(krate, self.trait_env.block, canonical.cast(Interner))
- .no_solution()
- {
- self.register_obligation(obligation.goal);
+ let goal: Goal = trait_ref.clone().cast(Interner);
+ if !self.try_obligation(goal.clone()).no_solution() {
+ self.register_obligation(goal);
let return_ty = self.normalize_projection_ty(projection);
for &fn_x in subtraits {
let fn_x_trait = fn_x.get_id(self.db, krate)?;
trait_ref.trait_id = to_chalk_trait_id(fn_x_trait);
- let obligation: chalk_ir::InEnvironment<chalk_ir::Goal<Interner>> =
- InEnvironment {
- goal: trait_ref.clone().cast(Interner),
- environment: trait_env.clone(),
- };
- let canonical = self.canonicalize(obligation.clone());
- if !self
- .db
- .trait_solve(krate, self.trait_env.block, canonical.cast(Interner))
- .no_solution()
- {
+ let goal = trait_ref.clone().cast(Interner);
+ if !self.try_obligation(goal).no_solution() {
return Some((fn_x, arg_tys, return_ty));
}
}
@@ -1165,20 +1158,26 @@ impl<'a> InferenceTable<'a> {
impl fmt::Debug for InferenceTable<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("InferenceTable").field("num_vars", &self.type_variable_table.len()).finish()
+ f.debug_struct("InferenceTable").finish()
}
}
mod resolve {
use super::InferenceTable;
use crate::{
- ConcreteConst, Const, ConstData, ConstScalar, ConstValue, DebruijnIndex, GenericArg,
- InferenceVar, Interner, Lifetime, Ty, TyVariableKind, VariableKind,
+ next_solver::mapping::ChalkToNextSolver, ConcreteConst, Const, ConstData, ConstScalar, ConstValue, DebruijnIndex, GenericArg, InferenceVar, Interner, Lifetime, Ty, TyVariableKind, VariableKind
};
use chalk_ir::{
cast::Cast,
fold::{TypeFoldable, TypeFolder},
};
+ use rustc_type_ir::{FloatVid, IntVid, TyVid};
+
+ #[derive(Copy, Clone, PartialEq, Eq)]
+ pub(super) enum VarKind {
+ Ty(TyVariableKind),
+ Const,
+ }
#[derive(chalk_derive::FallibleTypeFolder)]
#[has_interner(Interner)]
@@ -1188,7 +1187,7 @@ mod resolve {
F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
> {
pub(super) table: &'a mut InferenceTable<'b>,
- pub(super) var_stack: &'a mut Vec<InferenceVar>,
+ pub(super) var_stack: &'a mut Vec<(InferenceVar, VarKind)>,
pub(super) fallback: F,
}
impl<F> TypeFolder<Interner> for Resolver<'_, '_, F>
@@ -1209,25 +1208,79 @@ mod resolve {
kind: TyVariableKind,
outer_binder: DebruijnIndex,
) -> Ty {
- let var = self.table.var_unification_table.inference_var_root(var);
- if self.var_stack.contains(&var) {
- // recursive type
- let default = self.table.fallback_value(var, kind).cast(Interner);
- return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
- .assert_ty_ref(Interner)
- .clone();
- }
- if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
- // known_ty may contain other variables that are known by now
- self.var_stack.push(var);
- let result = known_ty.fold_with(self, outer_binder);
- self.var_stack.pop();
- result.assert_ty_ref(Interner).clone()
- } else {
- let default = self.table.fallback_value(var, kind).cast(Interner);
- (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
- .assert_ty_ref(Interner)
- .clone()
+ match kind {
+ TyVariableKind::General => {
+ let vid = self.table.infer_ctxt.root_var(TyVid::from(var.index()));
+ let var = InferenceVar::from(vid.as_u32());
+ if self.var_stack.contains(&(var, VarKind::Ty(kind))) {
+ // recursive type
+ let default = self.table.fallback_value(var, kind).cast(Interner);
+ return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+ .assert_ty_ref(Interner)
+ .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);
+ // 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);
+ self.var_stack.pop();
+ result
+ } else {
+ let default = self.table.fallback_value(var, kind).cast(Interner);
+ (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+ .assert_ty_ref(Interner)
+ .clone()
+ }
+ }
+ TyVariableKind::Integer => {
+ 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
+ let default = self.table.fallback_value(var, kind).cast(Interner);
+ return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+ .assert_ty_ref(Interner)
+ .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);
+ // 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);
+ self.var_stack.pop();
+ result
+ } else {
+ let default = self.table.fallback_value(var, kind).cast(Interner);
+ (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+ .assert_ty_ref(Interner)
+ .clone()
+ }
+ }
+ TyVariableKind::Float => {
+ 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
+ let default = self.table.fallback_value(var, kind).cast(Interner);
+ return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+ .assert_ty_ref(Interner)
+ .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);
+ // 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);
+ self.var_stack.pop();
+ result
+ } else {
+ let default = self.table.fallback_value(var, kind).cast(Interner);
+ (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+ .assert_ty_ref(Interner)
+ .clone()
+ }
+ }
}
}
@@ -1237,25 +1290,27 @@ mod resolve {
var: InferenceVar,
outer_binder: DebruijnIndex,
) -> Const {
- let var = self.table.var_unification_table.inference_var_root(var);
+ 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(),
value: ConstValue::Concrete(ConcreteConst { interned: ConstScalar::Unknown }),
}
.intern(Interner)
.cast(Interner);
- if self.var_stack.contains(&var) {
+ if self.var_stack.contains(&(var, VarKind::Const)) {
// recursive
return (self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
.assert_const_ref(Interner)
.clone();
}
- if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
+ 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);
// known_ty may contain other variables that are known by now
- self.var_stack.push(var);
- let result = known_ty.fold_with(self, outer_binder);
+ self.var_stack.push((var, VarKind::Const));
+ let result = known_const.fold_with(self, outer_binder);
self.var_stack.pop();
- result.assert_const_ref(Interner).clone()
+ result
} else {
(self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
.assert_const_ref(Interner)
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index c16bbb7b99..323ea951a9 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -957,23 +957,13 @@ pub fn callable_sig_from_fn_trait(
)
.build();
- let block = trait_env.block;
- let trait_env = trait_env.env.clone();
- let obligation =
- InEnvironment { goal: trait_ref.clone().cast(Interner), environment: trait_env.clone() };
- let canonical = table.canonicalize(obligation.clone());
- if !db.trait_solve(krate, block, canonical.cast(Interner)).no_solution() {
- table.register_obligation(obligation.goal);
+ if !table.try_obligation(trait_ref.clone().cast(Interner)).no_solution() {
+ table.register_obligation(trait_ref.clone().cast(Interner));
let return_ty = table.normalize_projection_ty(projection);
for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] {
let fn_x_trait = fn_x.get_id(db, krate)?;
trait_ref.trait_id = to_chalk_trait_id(fn_x_trait);
- let obligation: chalk_ir::InEnvironment<chalk_ir::Goal<Interner>> = InEnvironment {
- goal: trait_ref.clone().cast(Interner),
- environment: trait_env.clone(),
- };
- let canonical = table.canonicalize(obligation.clone());
- if !db.trait_solve(krate, block, canonical.cast(Interner)).no_solution() {
+ if !table.try_obligation(trait_ref.clone().cast(Interner)).no_solution() {
let ret_ty = table.resolve_completely(return_ty);
let args_ty = table.resolve_completely(args_ty);
let params = args_ty
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index f0be352fdd..ee223059d1 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -16,25 +16,13 @@ use hir_def::{
use hir_expand::name::Name;
use intern::sym;
use rustc_hash::{FxHashMap, FxHashSet};
-use rustc_type_ir::inherent::{IntoKind, SliceLike};
+use rustc_type_ir::inherent::{IntoKind, SliceLike, Ty as _};
use smallvec::{SmallVec, smallvec};
use stdx::never;
use triomphe::Arc;
use crate::{
- AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, GenericArgData,
- Goal, InEnvironment, Interner, Mutability, Scalar, Substitution, TraitEnvironment, TraitRef,
- TraitRefExt, Ty, TyBuilder, TyExt, TyKind, TyVariableKind, VariableKind, WhereClause,
- autoderef::{self, AutoderefKind},
- db::HirDatabase,
- error_lifetime, from_chalk_trait_id, from_foreign_def_id,
- infer::{Adjust, Adjustment, OverloadedDeref, PointerCast, unify::InferenceTable},
- lang_items::is_box,
- next_solver::SolverDefId,
- primitive::{FloatTy, IntTy, UintTy},
- to_chalk_trait_id,
- traits::NextTraitSolveResult,
- utils::all_super_traits,
+ autoderef::{self, AutoderefKind}, db::HirDatabase, from_chalk_trait_id, from_foreign_def_id, infer::{unify::InferenceTable, Adjust, Adjustment, OverloadedDeref, PointerCast}, lang_items::is_box, next_solver::{mapping::ChalkToNextSolver, SolverDefId}, primitive::{FloatTy, IntTy, UintTy}, to_chalk_trait_id, traits::{next_trait_solve_canonical}, utils::all_super_traits, AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, GenericArgData, Goal, InEnvironment, Interner, Mutability, Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, TyVariableKind, VariableKind, WhereClause
};
/// This is used as a key for indexing impls.
@@ -533,9 +521,9 @@ pub fn def_crates(db: &dyn HirDatabase, ty: &Ty, cur_crate: Crate) -> Option<Sma
}
/// Look up the method with the given name.
-pub(crate) fn lookup_method(
- db: &dyn HirDatabase,
- ty: &Canonical<Ty>,
+pub(crate) fn lookup_method<'db>(
+ db: &'db dyn HirDatabase,
+ ty: &crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
env: Arc<TraitEnvironment>,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
@@ -697,9 +685,9 @@ impl ReceiverAdjustments {
// This would be nicer if it just returned an iterator, but that runs into
// lifetime problems, because we need to borrow temp `CrateImplDefs`.
// FIXME add a context type here?
-pub(crate) fn iterate_method_candidates<T>(
- ty: &Canonical<Ty>,
- db: &dyn HirDatabase,
+pub(crate) fn iterate_method_candidates<'db, T>(
+ ty: &crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
+ db: &'db dyn HirDatabase,
env: Arc<TraitEnvironment>,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
@@ -1046,9 +1034,9 @@ pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool {
is_not_orphan
}
-pub fn iterate_path_candidates(
- ty: &Canonical<Ty>,
- db: &dyn HirDatabase,
+pub fn iterate_path_candidates<'db>(
+ ty: &crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
+ db: &'db dyn HirDatabase,
env: Arc<TraitEnvironment>,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
@@ -1068,9 +1056,9 @@ pub fn iterate_path_candidates(
)
}
-pub fn iterate_method_candidates_dyn(
- ty: &Canonical<Ty>,
- db: &dyn HirDatabase,
+pub fn iterate_method_candidates_dyn<'db>(
+ ty: &crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
+ db: &'db dyn HirDatabase,
env: Arc<TraitEnvironment>,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
@@ -1108,7 +1096,7 @@ pub fn iterate_method_candidates_dyn(
// types*.
let mut table = InferenceTable::new(db, env);
- let ty = table.instantiate_canonical(ty.clone());
+ let ty = table.instantiate_canonical_ns(ty.clone());
let deref_chain = autoderef_method_receiver(&mut table, ty);
deref_chain.into_iter().try_for_each(|(receiver_ty, adj)| {
@@ -1139,20 +1127,22 @@ pub fn iterate_method_candidates_dyn(
}
#[tracing::instrument(skip_all, fields(name = ?name))]
-fn iterate_method_candidates_with_autoref(
- table: &mut InferenceTable<'_>,
- receiver_ty: Canonical<Ty>,
+fn iterate_method_candidates_with_autoref<'db>(
+ table: &mut InferenceTable<'db>,
+ receiver_ty: crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
first_adjustment: ReceiverAdjustments,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
name: Option<&Name>,
callback: &mut dyn MethodCandidateCallback,
) -> ControlFlow<()> {
- if receiver_ty.value.is_general_var(Interner, &receiver_ty.binders) {
+ if matches!(receiver_ty.value.kind(), rustc_type_ir::TyKind::Bound(..)) {
// don't try to resolve methods on unknown types
return ControlFlow::Continue(());
}
+ let interner = table.interner;
+
let mut iterate_method_candidates_by_receiver = move |receiver_ty, first_adjustment| {
iterate_method_candidates_by_receiver(
table,
@@ -1166,7 +1156,11 @@ fn iterate_method_candidates_with_autoref(
};
let mut maybe_reborrowed = first_adjustment.clone();
- if let Some((_, _, m)) = receiver_ty.value.as_reference() {
+ if let rustc_type_ir::TyKind::Ref(_, _, m) = receiver_ty.value.kind() {
+ let m = match m {
+ rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut,
+ rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not,
+ };
// Prefer reborrow of references to move
maybe_reborrowed.autoref = Some(AutorefOrPtrAdjustment::Autoref(m));
maybe_reborrowed.autoderefs += 1;
@@ -1174,10 +1168,10 @@ fn iterate_method_candidates_with_autoref(
iterate_method_candidates_by_receiver(receiver_ty.clone(), maybe_reborrowed)?;
- let refed = Canonical {
- value: TyKind::Ref(Mutability::Not, error_lifetime(), receiver_ty.value.clone())
- .intern(Interner),
- binders: receiver_ty.binders.clone(),
+ let refed = crate::next_solver::Canonical {
+ max_universe: receiver_ty.max_universe,
+ variables: receiver_ty.variables,
+ value: crate::next_solver::Ty::new_ref(interner, crate::next_solver::Region::error(interner), receiver_ty.value, rustc_ast_ir::Mutability::Not),
};
iterate_method_candidates_by_receiver(
@@ -1185,10 +1179,10 @@ fn iterate_method_candidates_with_autoref(
first_adjustment.with_autoref(AutorefOrPtrAdjustment::Autoref(Mutability::Not)),
)?;
- let ref_muted = Canonical {
- value: TyKind::Ref(Mutability::Mut, error_lifetime(), receiver_ty.value.clone())
- .intern(Interner),
- binders: receiver_ty.binders.clone(),
+ let ref_muted = crate::next_solver::Canonical {
+ max_universe: receiver_ty.max_universe,
+ variables: receiver_ty.variables,
+ value: crate::next_solver::Ty::new_ref(interner, crate::next_solver::Region::error(interner), receiver_ty.value, rustc_ast_ir::Mutability::Mut),
};
iterate_method_candidates_by_receiver(
@@ -1196,10 +1190,11 @@ fn iterate_method_candidates_with_autoref(
first_adjustment.with_autoref(AutorefOrPtrAdjustment::Autoref(Mutability::Mut)),
)?;
- if let Some((ty, Mutability::Mut)) = receiver_ty.value.as_raw_ptr() {
- let const_ptr_ty = Canonical {
- value: TyKind::Raw(Mutability::Not, ty.clone()).intern(Interner),
- binders: receiver_ty.binders,
+ if let rustc_type_ir::TyKind::RawPtr(ty, rustc_ast_ir::Mutability::Mut) = receiver_ty.value.kind() {
+ let const_ptr_ty = rustc_type_ir::Canonical {
+ max_universe: rustc_type_ir::UniverseIndex::ZERO,
+ value: crate::next_solver::Ty::new_ptr(interner, ty, rustc_ast_ir::Mutability::Not),
+ variables: receiver_ty.variables,
};
iterate_method_candidates_by_receiver(
const_ptr_ty,
@@ -1250,16 +1245,17 @@ where
}
#[tracing::instrument(skip_all, fields(name = ?name))]
-fn iterate_method_candidates_by_receiver(
- table: &mut InferenceTable<'_>,
- receiver_ty: Canonical<Ty>,
+fn iterate_method_candidates_by_receiver<'db>(
+ table: &mut InferenceTable<'db>,
+ receiver_ty: crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
receiver_adjustments: ReceiverAdjustments,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
name: Option<&Name>,
callback: &mut dyn MethodCandidateCallback,
) -> ControlFlow<()> {
- let receiver_ty = table.instantiate_canonical(receiver_ty);
+ let receiver_ty = table.instantiate_canonical_ns(receiver_ty);
+ let receiver_ty: crate::Ty = ChalkToNextSolver::from_nextsolver(receiver_ty, table.interner);
// We're looking for methods with *receiver* type receiver_ty. These could
// be found in any of the derefs of receiver_ty, so we have to go through
// that, including raw derefs.
@@ -1307,9 +1303,9 @@ fn iterate_method_candidates_by_receiver(
}
#[tracing::instrument(skip_all, fields(name = ?name))]
-fn iterate_method_candidates_for_self_ty(
- self_ty: &Canonical<Ty>,
- db: &dyn HirDatabase,
+fn iterate_method_candidates_for_self_ty<'db>(
+ self_ty: &crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
+ db: &'db dyn HirDatabase,
env: Arc<TraitEnvironment>,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
@@ -1317,7 +1313,7 @@ fn iterate_method_candidates_for_self_ty(
callback: &mut dyn MethodCandidateCallback,
) -> ControlFlow<()> {
let mut table = InferenceTable::new(db, env);
- let self_ty = table.instantiate_canonical(self_ty.clone());
+ let self_ty = ChalkToNextSolver::from_nextsolver(table.instantiate_canonical_ns(self_ty.clone()), table.interner);
iterate_inherent_methods(
&self_ty,
&mut table,
@@ -1354,7 +1350,7 @@ fn iterate_trait_method_candidates(
) -> ControlFlow<()> {
let db = table.db;
- let canonical_self_ty = table.canonicalize(self_ty.clone());
+ let canonical_self_ty = ChalkToNextSolver::from_nextsolver(table.canonicalize(self_ty.clone().to_nextsolver(table.interner)), table.interner);
let TraitEnvironment { krate, block, .. } = *table.trait_env;
'traits: for &t in traits_in_scope {
@@ -1583,13 +1579,14 @@ pub(crate) fn resolve_indexing_op(
) -> Option<ReceiverAdjustments> {
let mut table = InferenceTable::new(db, env);
let ty = table.instantiate_canonical(ty);
- let deref_chain = autoderef_method_receiver(&mut table, ty);
+ let interner = table.interner;
+ let deref_chain = autoderef_method_receiver(&mut table, ty.to_nextsolver(interner));
for (ty, adj) in deref_chain {
- let goal = generic_implements_goal(db, &table.trait_env, index_trait, &ty);
- if !db
- .trait_solve(table.trait_env.krate, table.trait_env.block, goal.cast(Interner))
- .no_solution()
- {
+ //let goal = generic_implements_goal_ns(db, &table.trait_env, index_trait, &ty);
+ let goal = generic_implements_goal(db, &table.trait_env, index_trait, &ChalkToNextSolver::from_nextsolver(ty, interner));
+ let goal: chalk_ir::Canonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>> = goal.cast(Interner);
+ let goal = goal.to_nextsolver(interner);
+ if !next_trait_solve_canonical(db, table.trait_env.krate, table.trait_env.block, goal).no_solution() {
return Some(adj);
}
}
@@ -1773,26 +1770,11 @@ fn is_valid_impl_fn_candidate(
});
for goal in goals.clone() {
- let in_env = InEnvironment::new(&table.trait_env.env, goal);
- let canonicalized = table.canonicalize_with_free_vars(in_env);
- let solution = table.db.trait_solve(
- table.trait_env.krate,
- table.trait_env.block,
- canonicalized.value.clone(),
- );
-
- match solution {
- NextTraitSolveResult::Certain(canonical_subst) => {
- canonicalized.apply_solution(
- table,
- Canonical {
- binders: canonical_subst.binders,
- value: canonical_subst.value.subst,
- },
- );
+ match table.solve_obligation(goal) {
+ Ok(_) => {}
+ Err(_) => {
+ return IsValidCandidate::No;
}
- NextTraitSolveResult::Uncertain(..) => {}
- NextTraitSolveResult::NoSolution => return IsValidCandidate::No,
}
}
@@ -1857,25 +1839,66 @@ fn generic_implements_goal(
Canonical { binders, value }
}
-fn autoderef_method_receiver(
- table: &mut InferenceTable<'_>,
- ty: Ty,
-) -> Vec<(Canonical<Ty>, ReceiverAdjustments)> {
- let mut deref_chain: Vec<_> = Vec::new();
- let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ty, false, true);
+/*
+/// This creates Substs for a trait with the given Self type and type variables
+/// for all other parameters, to query the trait solver with it.
+#[tracing::instrument(skip_all)]
+fn generic_implements_goal_ns<'db>(
+ db: &'db dyn HirDatabase,
+ interner: DbInterner<'db>,
+ env: &TraitEnvironment,
+ trait_: TraitId,
+ self_ty: &crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
+) -> crate::next_solver::Canonical<'db, crate::next_solver::Goal<'db, crate::next_solver::Predicate<'db>>> {
+ let variables = self_ty.variables;
+ let trait_ref = TyBuilder::trait_ref(db, trait_)
+ .push(ChalkToNextSolver::from_nextsolver(self_ty.value, interner))
+ .fill_with_bound_vars(DebruijnIndex::INNERMOST, variables.len())
+ .build();
+
+ let infer_ctxt = interner.infer_ctxt().build(TypingMode::non_body_analysis());
+ let args = infer_ctxt.fresh_args_for_item(SolverDefId::TraitId(trait_));
+
+ rustc_type_ir::TraitRef::new(interner, SolverDefId::TraitId(trait_)).with_self_ty(interner, self_ty.value);
+
+
+ let kinds =
+ binders.iter().cloned().chain(trait_ref.substitution.iter(Interner).skip(1).map(|it| {
+ let vk = match it.data(Interner) {
+ GenericArgData::Ty(_) => VariableKind::Ty(chalk_ir::TyVariableKind::General),
+ GenericArgData::Lifetime(_) => VariableKind::Lifetime,
+ GenericArgData::Const(c) => VariableKind::Const(c.data(Interner).ty.clone()),
+ };
+ WithKind::new(vk, UniverseIndex::ROOT)
+ }));
+ let binders = CanonicalVarKinds::from_iter(Interner, kinds);
+
+ let obligation = trait_ref.cast(Interner);
+ let value = InEnvironment::new(&env.env, obligation);
+ crate::next_solver::Canonical { max_universe, value, variables }
+}
+*/
+
+fn autoderef_method_receiver<'db>(
+ table: &mut InferenceTable<'db>,
+ ty: crate::next_solver::Ty<'db>,
+) -> Vec<(crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, ReceiverAdjustments)> {
+ let interner = table.interner;
+ let mut deref_chain = Vec::new();
+ let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ChalkToNextSolver::from_nextsolver(ty, interner), false, true);
while let Some((ty, derefs)) = autoderef.next() {
deref_chain.push((
- autoderef.table.canonicalize(ty),
+ autoderef.table.canonicalize(ty.to_nextsolver(interner)),
ReceiverAdjustments { autoref: None, autoderefs: derefs, unsize_array: false },
));
}
// As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!)
- if let Some((TyKind::Array(parameters, _), binders, adj)) =
- deref_chain.last().map(|(ty, adj)| (ty.value.kind(Interner), ty.binders.clone(), adj))
+ if let Some((rustc_type_ir::Array(parameters, _), variables, max_universe, adj)) =
+ deref_chain.last().map(|d| (d.0.value.kind(), d.0.variables.clone(), d.0.max_universe, d.1.clone()))
{
- let unsized_ty = TyKind::Slice(parameters.clone()).intern(Interner);
+ let unsized_ty = crate::next_solver::Ty::new_slice(interner, parameters);
deref_chain.push((
- Canonical { value: unsized_ty, binders },
+ crate::next_solver::Canonical { max_universe, value: unsized_ty, variables, },
ReceiverAdjustments { unsize_array: true, ..adj.clone() },
));
}
diff --git a/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs b/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs
new file mode 100644
index 0000000000..0820006e5d
--- /dev/null
+++ b/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs
@@ -0,0 +1,785 @@
+
+use rustc_hash::FxHashMap;
+use rustc_index::Idx;
+use rustc_type_ir::inherent::{Const as _, IntoKind as _, Region as _, SliceLike, Ty as _};
+use rustc_type_ir::InferTy::{self, FloatVar, IntVar, TyVar};
+use rustc_type_ir::{BoundVar, CanonicalQueryInput, CanonicalTyVarKind, DebruijnIndex, Flags, InferConst, RegionKind, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UniverseIndex};
+use smallvec::SmallVec;
+use tracing::debug;
+
+use crate::next_solver::infer::InferCtxt;
+use crate::next_solver::{Binder, BoundRegion, BoundRegionKind, BoundTy, Canonical, CanonicalVarKind, CanonicalVars, Const, ConstKind, DbInterner, GenericArg, ParamEnvAnd, Placeholder, Region, Ty, TyKind};
+
+/// When we canonicalize a value to form a query, we wind up replacing
+/// various parts of it with canonical variables. This struct stores
+/// those replaced bits to remember for when we process the query
+/// result.
+#[derive(Clone, Debug)]
+pub struct OriginalQueryValues<'db> {
+ /// Map from the universes that appear in the query to the universes in the
+ /// caller context. For all queries except `evaluate_goal` (used by Chalk),
+ /// we only ever put ROOT values into the query, so this map is very
+ /// simple.
+ pub universe_map: SmallVec<[UniverseIndex; 4]>,
+
+ /// This is equivalent to `CanonicalVarValues`, but using a
+ /// `SmallVec` yields a significant performance win.
+ pub var_values: SmallVec<[GenericArg<'db>; 8]>,
+}
+
+impl<'db> Default for OriginalQueryValues<'db> {
+ fn default() -> Self {
+ let mut universe_map = SmallVec::default();
+ universe_map.push(UniverseIndex::ROOT);
+
+ Self { universe_map, var_values: SmallVec::default() }
+ }
+}
+
+impl<'db> InferCtxt<'db> {
+ /// Canonicalizes a query value `V`. When we canonicalize a query,
+ /// we not only canonicalize unbound inference variables, but we
+ /// *also* replace all free regions whatsoever. So for example a
+ /// query like `T: Trait<'static>` would be canonicalized to
+ ///
+ /// ```text
+ /// T: Trait<'?0>
+ /// ```
+ ///
+ /// with a mapping M that maps `'?0` to `'static`.
+ ///
+ /// To get a good understanding of what is happening here, check
+ /// out the [chapter in the rustc dev guide][c].
+ ///
+ /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query
+ pub fn canonicalize_query<V>(
+ &self,
+ value: ParamEnvAnd<'db, V>,
+ query_state: &mut OriginalQueryValues<'db>,
+ ) -> CanonicalQueryInput<DbInterner<'db>, ParamEnvAnd<'db, V>>
+ where
+ V: TypeFoldable<DbInterner<'db>>,
+ {
+ let (param_env, value) = value.into_parts();
+ // FIXME(#118965): We don't canonicalize the static lifetimes that appear in the
+ // `param_env` because they are treated differently by trait selection.
+ let canonical_param_env = Canonicalizer::canonicalize(
+ param_env,
+ None,
+ self.interner,
+ &CanonicalizeFreeRegionsOtherThanStatic,
+ query_state,
+ );
+
+ let canonical = Canonicalizer::canonicalize_with_base(
+ canonical_param_env,
+ value,
+ Some(self),
+ self.interner,
+ &CanonicalizeAllFreeRegions,
+ query_state,
+ )
+ .unchecked_map(|(param_env, value)| ParamEnvAnd { param_env, value });
+ CanonicalQueryInput { canonical, typing_mode: self.typing_mode() }
+ }
+
+ /// Canonicalizes a query *response* `V`. When we canonicalize a
+ /// query response, we only canonicalize unbound inference
+ /// variables, and we leave other free regions alone. So,
+ /// continuing with the example from `canonicalize_query`, if
+ /// there was an input query `T: Trait<'static>`, it would have
+ /// been canonicalized to
+ ///
+ /// ```text
+ /// T: Trait<'?0>
+ /// ```
+ ///
+ /// with a mapping M that maps `'?0` to `'static`. But if we found that there
+ /// exists only one possible impl of `Trait`, and it looks like
+ /// ```ignore (illustrative)
+ /// impl<T> Trait<'static> for T { .. }
+ /// ```
+ /// then we would prepare a query result R that (among other
+ /// things) includes a mapping to `'?0 := 'static`. When
+ /// canonicalizing this query result R, we would leave this
+ /// reference to `'static` alone.
+ ///
+ /// To get a good understanding of what is happening here, check
+ /// out the [chapter in the rustc dev guide][c].
+ ///
+ /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query-result
+ pub fn canonicalize_response<V>(&self, value: V) -> Canonical<'db, V>
+ where
+ V: TypeFoldable<DbInterner<'db>>,
+ {
+ let mut query_state = OriginalQueryValues::default();
+ Canonicalizer::canonicalize(
+ value,
+ Some(self),
+ self.interner,
+ &CanonicalizeQueryResponse,
+ &mut query_state,
+ )
+ }
+
+ pub fn canonicalize_user_type_annotation<V>(&self, value: V) -> Canonical<'db, V>
+ where
+ V: TypeFoldable<DbInterner<'db>>,
+ {
+ let mut query_state = OriginalQueryValues::default();
+ Canonicalizer::canonicalize(
+ value,
+ Some(self),
+ self.interner,
+ &CanonicalizeUserTypeAnnotation,
+ &mut query_state,
+ )
+ }
+}
+
+/// Controls how we canonicalize "free regions" that are not inference
+/// variables. This depends on what we are canonicalizing *for* --
+/// e.g., if we are canonicalizing to create a query, we want to
+/// replace those with inference variables, since we want to make a
+/// maximally general query. But if we are canonicalizing a *query
+/// response*, then we don't typically replace free regions, as they
+/// must have been introduced from other parts of the system.
+trait CanonicalizeMode {
+ fn canonicalize_free_region<'db>(
+ &self,
+ canonicalizer: &mut Canonicalizer<'_, 'db>,
+ r: Region<'db>,
+ ) -> Region<'db>;
+
+ fn any(&self) -> bool;
+
+ // Do we preserve universe of variables.
+ fn preserve_universes(&self) -> bool;
+}
+
+struct CanonicalizeQueryResponse;
+
+impl CanonicalizeMode for CanonicalizeQueryResponse {
+ fn canonicalize_free_region<'db>(
+ &self,
+ canonicalizer: &mut Canonicalizer<'_, 'db>,
+ mut r: Region<'db>,
+ ) -> Region<'db> {
+ let infcx = canonicalizer.infcx.unwrap();
+
+ if let RegionKind::ReVar(vid) = r.kind() {
+ r = infcx
+ .inner
+ .borrow_mut()
+ .unwrap_region_constraints()
+ .opportunistic_resolve_var(canonicalizer.tcx, vid);
+ debug!(
+ "canonical: region var found with vid {vid:?}, \
+ opportunistically resolved to {r:?}",
+ );
+ };
+
+ match r.kind() {
+ RegionKind::ReLateParam(_) | RegionKind::ReErased | RegionKind::ReStatic | RegionKind::ReEarlyParam(..) | RegionKind::ReError(..) => r,
+
+ RegionKind::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region(
+ CanonicalVarKind::PlaceholderRegion(placeholder),
+ r,
+ ),
+
+ RegionKind::ReVar(vid) => {
+ let universe = infcx
+ .inner
+ .borrow_mut()
+ .unwrap_region_constraints()
+ .probe_value(vid)
+ .unwrap_err();
+ canonicalizer.canonical_var_for_region(
+ CanonicalVarKind::Region(universe),
+ r,
+ )
+ }
+
+ _ => {
+ // Other than `'static` or `'empty`, the query
+ // response should be executing in a fully
+ // canonicalized environment, so there shouldn't be
+ // any other region names it can come up.
+ //
+ // rust-lang/rust#57464: `impl Trait` can leak local
+ // scopes (in manner violating typeck). Therefore, use
+ // `delayed_bug` to allow type error over an ICE.
+ panic!("unexpected region in query response: `{r:?}`");
+ }
+ }
+ }
+
+ fn any(&self) -> bool {
+ false
+ }
+
+ fn preserve_universes(&self) -> bool {
+ true
+ }
+}
+
+struct CanonicalizeUserTypeAnnotation;
+
+impl CanonicalizeMode for CanonicalizeUserTypeAnnotation {
+ fn canonicalize_free_region<'db>(
+ &self,
+ canonicalizer: &mut Canonicalizer<'_, 'db>,
+ r: Region<'db>,
+ ) -> Region<'db> {
+ match r.kind() {
+ RegionKind::ReEarlyParam(_)
+ | RegionKind::ReLateParam(_)
+ | RegionKind::ReErased
+ | RegionKind::ReStatic
+ | RegionKind::ReError(_) => r,
+ RegionKind::ReVar(_) => canonicalizer.canonical_var_for_region_in_root_universe(r),
+ RegionKind::RePlaceholder(..) | RegionKind::ReBound(..) => {
+ // We only expect region names that the user can type.
+ panic!("unexpected region in query response: `{:?}`", r)
+ }
+ }
+ }
+
+ fn any(&self) -> bool {
+ false
+ }
+
+ fn preserve_universes(&self) -> bool {
+ false
+ }
+}
+
+struct CanonicalizeAllFreeRegions;
+
+impl CanonicalizeMode for CanonicalizeAllFreeRegions {
+ fn canonicalize_free_region<'db>(
+ &self,
+ canonicalizer: &mut Canonicalizer<'_, 'db>,
+ r: Region<'db>,
+ ) -> Region<'db> {
+ canonicalizer.canonical_var_for_region_in_root_universe(r)
+ }
+
+ fn any(&self) -> bool {
+ true
+ }
+
+ fn preserve_universes(&self) -> bool {
+ false
+ }
+}
+
+struct CanonicalizeFreeRegionsOtherThanStatic;
+
+impl CanonicalizeMode for CanonicalizeFreeRegionsOtherThanStatic {
+ fn canonicalize_free_region<'db>(
+ &self,
+ canonicalizer: &mut Canonicalizer<'_, 'db>,
+ r: Region<'db>,
+ ) -> Region<'db> {
+ if r.is_static() { r } else { canonicalizer.canonical_var_for_region_in_root_universe(r) }
+ }
+
+ fn any(&self) -> bool {
+ true
+ }
+
+ fn preserve_universes(&self) -> bool {
+ false
+ }
+}
+
+struct Canonicalizer<'cx, 'db> {
+ /// Set to `None` to disable the resolution of inference variables.
+ infcx: Option<&'cx InferCtxt<'db>>,
+ tcx: DbInterner<'db>,
+ variables: SmallVec<[CanonicalVarKind<'db>; 8]>,
+ query_state: &'cx mut OriginalQueryValues<'db>,
+ // Note that indices is only used once `var_values` is big enough to be
+ // heap-allocated.
+ indices: FxHashMap<GenericArg<'db>, BoundVar>,
+ canonicalize_mode: &'cx dyn CanonicalizeMode,
+ needs_canonical_flags: TypeFlags,
+
+ binder_index: DebruijnIndex,
+}
+
+impl<'cx, 'db> TypeFolder<DbInterner<'db>> for Canonicalizer<'cx, 'db> {
+ fn cx(&self) -> DbInterner<'db> {
+ self.tcx
+ }
+
+ fn fold_binder<T>(&mut self, t: Binder<'db, T>) -> Binder<'db, T>
+ where
+ T: TypeFoldable<DbInterner<'db>>,
+ {
+ self.binder_index.shift_in(1);
+ let t = t.super_fold_with(self);
+ self.binder_index.shift_out(1);
+ t
+ }
+
+ fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
+ match r.kind() {
+ RegionKind::ReBound(index, ..) => {
+ if index >= self.binder_index {
+ panic!("escaping late-bound region during canonicalization");
+ } else {
+ r
+ }
+ }
+
+ RegionKind::ReStatic
+ | RegionKind::ReEarlyParam(..)
+ | RegionKind::ReError(_)
+ | RegionKind::ReLateParam(_)
+ | RegionKind::RePlaceholder(..)
+ | RegionKind::ReVar(_)
+ | RegionKind::ReErased => self.canonicalize_mode.canonicalize_free_region(self, r),
+ }
+ }
+
+ fn fold_ty(&mut self, mut t: Ty<'db>) -> Ty<'db> {
+ match t.kind() {
+ TyKind::Infer(TyVar(mut vid)) => {
+ // We need to canonicalize the *root* of our ty var.
+ // This is so that our canonical response correctly reflects
+ // any equated inference vars correctly!
+ let root_vid = self.infcx.unwrap().root_var(vid);
+ if root_vid != vid {
+ t = Ty::new_var(self.tcx, root_vid);
+ vid = root_vid;
+ }
+
+ debug!("canonical: type var found with vid {:?}", vid);
+ match self.infcx.unwrap().probe_ty_var(vid) {
+ // `t` could be a float / int variable; canonicalize that instead.
+ Ok(t) => {
+ debug!("(resolved to {:?})", t);
+ self.fold_ty(t)
+ }
+
+ // `TyVar(vid)` is unresolved, track its universe index in the canonicalized
+ // result.
+ Err(mut ui) => {
+ if !self.canonicalize_mode.preserve_universes() {
+ // FIXME: perf problem described in #55921.
+ ui = UniverseIndex::ROOT;
+ }
+ self.canonicalize_ty_var(
+ CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
+ t,
+ )
+ }
+ }
+ }
+
+ TyKind::Infer(IntVar(vid)) => {
+ let nt = self.infcx.unwrap().opportunistic_resolve_int_var(vid);
+ if nt != t {
+ return self.fold_ty(nt);
+ } else {
+ self.canonicalize_ty_var(
+ CanonicalVarKind::Ty(CanonicalTyVarKind::Int),
+ t,
+ )
+ }
+ }
+ TyKind::Infer(FloatVar(vid)) => {
+ let nt = self.infcx.unwrap().opportunistic_resolve_float_var(vid);
+ if nt != t {
+ return self.fold_ty(nt);
+ } else {
+ self.canonicalize_ty_var(
+ CanonicalVarKind::Ty(CanonicalTyVarKind::Float),
+ t,
+ )
+ }
+ }
+
+ TyKind::Infer(InferTy::FreshTy(_) | InferTy::FreshIntTy(_) | InferTy::FreshFloatTy(_)) => {
+ panic!("encountered a fresh type during canonicalization")
+ }
+
+ TyKind::Placeholder(mut placeholder) => {
+ if !self.canonicalize_mode.preserve_universes() {
+ placeholder.universe = UniverseIndex::ROOT;
+ }
+ self.canonicalize_ty_var(
+ CanonicalVarKind::PlaceholderTy(placeholder),
+ t,
+ )
+ }
+
+ TyKind::Bound(debruijn, _) => {
+ if debruijn >= self.binder_index {
+ panic!("escaping bound type during canonicalization")
+ } else {
+ t
+ }
+ }
+
+ TyKind::Closure(..)
+ | TyKind::CoroutineClosure(..)
+ | TyKind::Coroutine(..)
+ | TyKind::CoroutineWitness(..)
+ | TyKind::Bool
+ | TyKind::Char
+ | TyKind::Int(..)
+ | TyKind::Uint(..)
+ | TyKind::Float(..)
+ | TyKind::Adt(..)
+ | TyKind::Str
+ | TyKind::Error(_)
+ | TyKind::Array(..)
+ | TyKind::Slice(..)
+ | TyKind::RawPtr(..)
+ | TyKind::Ref(..)
+ | TyKind::FnDef(..)
+ | TyKind::FnPtr(..)
+ | TyKind::Dynamic(..)
+ | TyKind::UnsafeBinder(_)
+ | TyKind::Never
+ | TyKind::Tuple(..)
+ | TyKind::Alias(..)
+ | TyKind::Foreign(..)
+ | TyKind::Pat(..)
+ | TyKind::Param(..) => {
+ if t.flags().intersects(self.needs_canonical_flags) {
+ t.super_fold_with(self)
+ } else {
+ t
+ }
+ }
+ }
+ }
+
+ fn fold_const(&mut self, mut ct: Const<'db>) -> Const<'db> {
+ match ct.kind() {
+ ConstKind::Infer(InferConst::Var(mut vid)) => {
+ // We need to canonicalize the *root* of our const var.
+ // This is so that our canonical response correctly reflects
+ // any equated inference vars correctly!
+ let root_vid = self.infcx.unwrap().root_const_var(vid);
+ if root_vid != vid {
+ ct = Const::new_var(self.tcx, root_vid);
+ vid = root_vid;
+ }
+
+ debug!("canonical: const var found with vid {:?}", vid);
+ match self.infcx.unwrap().probe_const_var(vid) {
+ Ok(c) => {
+ debug!("(resolved to {:?})", c);
+ return self.fold_const(c);
+ }
+
+ // `ConstVar(vid)` is unresolved, track its universe index in the
+ // canonicalized result
+ Err(mut ui) => {
+ if !self.canonicalize_mode.preserve_universes() {
+ // FIXME: perf problem described in #55921.
+ ui = UniverseIndex::ROOT;
+ }
+ return self.canonicalize_const_var(
+ CanonicalVarKind::Const(ui),
+ ct,
+ );
+ }
+ }
+ }
+ ConstKind::Infer(InferConst::Fresh(_)) => {
+ panic!("encountered a fresh const during canonicalization")
+ }
+ ConstKind::Bound(debruijn, _) => {
+ if debruijn >= self.binder_index {
+ panic!("escaping bound const during canonicalization")
+ } else {
+ return ct;
+ }
+ }
+ ConstKind::Placeholder(placeholder) => {
+ return self.canonicalize_const_var(
+ CanonicalVarKind::PlaceholderConst(placeholder),
+ ct,
+ );
+ }
+ _ => {}
+ }
+
+ if ct.flags().intersects(self.needs_canonical_flags) {
+ ct.super_fold_with(self)
+ } else {
+ ct
+ }
+ }
+}
+
+impl<'cx, 'db> Canonicalizer<'cx, 'db> {
+ /// The main `canonicalize` method, shared impl of
+ /// `canonicalize_query` and `canonicalize_response`.
+ fn canonicalize<V>(
+ value: V,
+ infcx: Option<&InferCtxt<'db>>,
+ tcx: DbInterner<'db>,
+ canonicalize_region_mode: &dyn CanonicalizeMode,
+ query_state: &mut OriginalQueryValues<'db>,
+ ) -> Canonical<'db, V>
+ where
+ V: TypeFoldable<DbInterner<'db>>,
+ {
+ let base = Canonical {
+ max_universe: UniverseIndex::ROOT,
+ variables: CanonicalVars::new_from_iter(tcx, []),
+ value: (),
+ };
+ Canonicalizer::canonicalize_with_base(
+ base,
+ value,
+ infcx,
+ tcx,
+ canonicalize_region_mode,
+ query_state,
+ )
+ .unchecked_map(|((), val)| val)
+ }
+
+ fn canonicalize_with_base<U, V>(
+ base: Canonical<'db, U>,
+ value: V,
+ infcx: Option<&InferCtxt<'db>>,
+ tcx: DbInterner<'db>,
+ canonicalize_region_mode: &dyn CanonicalizeMode,
+ query_state: &mut OriginalQueryValues<'db>,
+ ) -> Canonical<'db, (U, V)>
+ where
+ V: TypeFoldable<DbInterner<'db>>,
+ {
+ let needs_canonical_flags = if canonicalize_region_mode.any() {
+ TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_FREE_REGIONS
+ } else {
+ TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER
+ };
+
+ // Fast path: nothing that needs to be canonicalized.
+ if !value.has_type_flags(needs_canonical_flags) {
+ return base.unchecked_map(|b| (b, value));
+ }
+
+ let mut canonicalizer = Canonicalizer {
+ infcx,
+ tcx,
+ canonicalize_mode: canonicalize_region_mode,
+ needs_canonical_flags,
+ variables: SmallVec::from_slice(base.variables.as_slice()),
+ query_state,
+ indices: FxHashMap::default(),
+ binder_index: DebruijnIndex::ZERO,
+ };
+ if canonicalizer.query_state.var_values.spilled() {
+ canonicalizer.indices = canonicalizer
+ .query_state
+ .var_values
+ .iter()
+ .enumerate()
+ .map(|(i, &kind)| (kind, BoundVar::from(i)))
+ .collect();
+ }
+ let out_value = value.fold_with(&mut canonicalizer);
+
+ // Once we have canonicalized `out_value`, it should not
+ // contain anything that ties it to this inference context
+ // anymore.
+ debug_assert!(!out_value.has_infer() && !out_value.has_placeholders());
+
+ let canonical_variables = CanonicalVars::new_from_iter(tcx, canonicalizer.universe_canonicalized_variables());
+
+ let max_universe = canonical_variables
+ .iter()
+ .map(|cvar| cvar.universe())
+ .max()
+ .unwrap_or(UniverseIndex::ROOT);
+
+ Canonical { max_universe, variables: canonical_variables, value: (base.value, out_value) }
+ }
+
+ /// Creates a canonical variable replacing `kind` from the input,
+ /// or returns an existing variable if `kind` has already been
+ /// seen. `kind` is expected to be an unbound variable (or
+ /// potentially a free region).
+ fn canonical_var(&mut self, info: CanonicalVarKind<'db>, kind: GenericArg<'db>) -> BoundVar {
+ let Canonicalizer { variables, query_state, indices, .. } = self;
+
+ let var_values = &mut query_state.var_values;
+
+ let universe = info.universe();
+ if universe != UniverseIndex::ROOT {
+ assert!(self.canonicalize_mode.preserve_universes());
+
+ // Insert universe into the universe map. To preserve the order of the
+ // universes in the value being canonicalized, we don't update the
+ // universe in `info` until we have finished canonicalizing.
+ match query_state.universe_map.binary_search(&universe) {
+ Err(idx) => query_state.universe_map.insert(idx, universe),
+ Ok(_) => {}
+ }
+ }
+
+ // This code is hot. `variables` and `var_values` are usually small
+ // (fewer than 8 elements ~95% of the time). They are SmallVec's to
+ // avoid allocations in those cases. We also don't use `indices` to
+ // determine if a kind has been seen before until the limit of 8 has
+ // been exceeded, to also avoid allocations for `indices`.
+ if !var_values.spilled() {
+ // `var_values` is stack-allocated. `indices` isn't used yet. Do a
+ // direct linear search of `var_values`.
+ if let Some(idx) = var_values.iter().position(|&k| k == kind) {
+ // `kind` is already present in `var_values`.
+ BoundVar::new(idx)
+ } else {
+ // `kind` isn't present in `var_values`. Append it. Likewise
+ // for `info` and `variables`.
+ variables.push(info);
+ var_values.push(kind);
+ assert_eq!(variables.len(), var_values.len());
+
+ // If `var_values` has become big enough to be heap-allocated,
+ // fill up `indices` to facilitate subsequent lookups.
+ if var_values.spilled() {
+ assert!(indices.is_empty());
+ *indices = var_values
+ .iter()
+ .enumerate()
+ .map(|(i, &kind)| (kind, BoundVar::new(i)))
+ .collect();
+ }
+ // The cv is the index of the appended element.
+ BoundVar::new(var_values.len() - 1)
+ }
+ } else {
+ // `var_values` is large. Do a hashmap search via `indices`.
+ *indices.entry(kind).or_insert_with(|| {
+ variables.push(info);
+ var_values.push(kind);
+ assert_eq!(variables.len(), var_values.len());
+ BoundVar::new(variables.len() - 1)
+ })
+ }
+ }
+
+ /// Replaces the universe indexes used in `var_values` with their index in
+ /// `query_state.universe_map`. This minimizes the maximum universe used in
+ /// the canonicalized value.
+ fn universe_canonicalized_variables(self) -> SmallVec<[CanonicalVarKind<'db>; 8]> {
+ if self.query_state.universe_map.len() == 1 {
+ return self.variables;
+ }
+
+ let reverse_universe_map: FxHashMap<UniverseIndex, UniverseIndex> = self
+ .query_state
+ .universe_map
+ .iter()
+ .enumerate()
+ .map(|(idx, universe)| (*universe, UniverseIndex::from_usize(idx)))
+ .collect();
+
+ self.variables
+ .iter()
+ .map(|v| match *v {
+ CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
+ return *v;
+ }
+ CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
+ CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u]))
+ }
+ CanonicalVarKind::Region(u) => {
+ CanonicalVarKind::Region(reverse_universe_map[&u])
+ }
+ CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]),
+ CanonicalVarKind::PlaceholderTy(placeholder) => {
+ CanonicalVarKind::PlaceholderTy(Placeholder {
+ universe: reverse_universe_map[&placeholder.universe],
+ ..placeholder
+ })
+ }
+ CanonicalVarKind::PlaceholderRegion(placeholder) => {
+ CanonicalVarKind::PlaceholderRegion(Placeholder {
+ universe: reverse_universe_map[&placeholder.universe],
+ ..placeholder
+ })
+ }
+ CanonicalVarKind::PlaceholderConst(placeholder) => {
+ CanonicalVarKind::PlaceholderConst(Placeholder {
+ universe: reverse_universe_map[&placeholder.universe],
+ ..placeholder
+ })
+ }
+ })
+ .collect()
+ }
+
+ /// Shorthand helper that creates a canonical region variable for
+ /// `r` (always in the root universe). The reason that we always
+ /// put these variables into the root universe is because this
+ /// method is used during **query construction:** in that case, we
+ /// are taking all the regions and just putting them into the most
+ /// generic context we can. This may generate solutions that don't
+ /// fit (e.g., that equate some region variable with a placeholder
+ /// it can't name) on the caller side, but that's ok, the caller
+ /// can figure that out. In the meantime, it maximizes our
+ /// caching.
+ ///
+ /// (This works because unification never fails -- and hence trait
+ /// selection is never affected -- due to a universe mismatch.)
+ fn canonical_var_for_region_in_root_universe(
+ &mut self,
+ r: Region<'db>,
+ ) -> Region<'db> {
+ self.canonical_var_for_region(
+ CanonicalVarKind::Region(UniverseIndex::ROOT),
+ r,
+ )
+ }
+
+ /// Creates a canonical variable (with the given `info`)
+ /// representing the region `r`; return a region referencing it.
+ fn canonical_var_for_region(
+ &mut self,
+ info: CanonicalVarKind<'db>,
+ r: Region<'db>,
+ ) -> Region<'db> {
+ let var = self.canonical_var(info, r.into());
+ let br = BoundRegion { var, kind: BoundRegionKind::Anon };
+ Region::new_bound(self.cx(), self.binder_index, br)
+ }
+
+ /// Given a type variable `ty_var` of the given kind, first check
+ /// if `ty_var` is bound to anything; if so, canonicalize
+ /// *that*. Otherwise, create a new canonical variable for
+ /// `ty_var`.
+ fn canonicalize_ty_var(&mut self, info: CanonicalVarKind<'db>, ty_var: Ty<'db>) -> Ty<'db> {
+ debug_assert!(!self.infcx.is_some_and(|infcx| ty_var != infcx.shallow_resolve(ty_var)));
+ let var = self.canonical_var(info, ty_var.into());
+ Ty::new_bound(self.tcx, self.binder_index, BoundTy { kind: crate::next_solver::BoundTyKind::Anon, var })
+ }
+
+ /// Given a type variable `const_var` of the given kind, first check
+ /// if `const_var` is bound to anything; if so, canonicalize
+ /// *that*. Otherwise, create a new canonical variable for
+ /// `const_var`.
+ fn canonicalize_const_var(
+ &mut self,
+ info: CanonicalVarKind<'db>,
+ const_var: Const<'db>,
+ ) -> Const<'db> {
+ debug_assert!(
+ !self.infcx.is_some_and(|infcx| const_var != infcx.shallow_resolve_const(const_var))
+ );
+ let var = self.canonical_var(info, const_var.into());
+ Const::new_bound(self.tcx, self.binder_index, var)
+ }
+}
diff --git a/crates/hir-ty/src/next_solver/infer/canonical/mod.rs b/crates/hir-ty/src/next_solver/infer/canonical/mod.rs
index 4457e1340d..ec41111ed8 100644
--- a/crates/hir-ty/src/next_solver/infer/canonical/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/canonical/mod.rs
@@ -42,6 +42,7 @@ use rustc_type_ir::{
},
};
+pub mod canonicalizer;
pub mod instantiate;
impl<'db> InferCtxt<'db> {
diff --git a/crates/hir-ty/src/next_solver/infer/mod.rs b/crates/hir-ty/src/next_solver/infer/mod.rs
index 585719144e..894c91e0f4 100644
--- a/crates/hir-ty/src/next_solver/infer/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/mod.rs
@@ -190,12 +190,13 @@ impl<'db> InferCtxtInner<'db> {
}
#[inline]
- fn int_unification_table(&mut self) -> UnificationTable<'_, 'db, IntVid> {
+ pub(crate) fn int_unification_table(&mut self) -> UnificationTable<'_, 'db, IntVid> {
+ tracing::debug!(?self.int_unification_storage);
self.int_unification_storage.with_log(&mut self.undo_log)
}
#[inline]
- fn float_unification_table(&mut self) -> UnificationTable<'_, 'db, FloatVid> {
+ pub(crate) fn float_unification_table(&mut self) -> UnificationTable<'_, 'db, FloatVid> {
self.float_unification_storage.with_log(&mut self.undo_log)
}
@@ -213,6 +214,7 @@ impl<'db> InferCtxtInner<'db> {
}
}
+#[derive(Clone)]
pub struct InferCtxt<'db> {
pub interner: DbInterner<'db>,
@@ -500,6 +502,10 @@ impl<'db> InferCtxt<'db> {
self.next_ty_var_with_origin(TypeVariableOrigin { param_def_id: None })
}
+ pub fn next_ty_vid(&self) -> TyVid {
+ self.inner.borrow_mut().type_variables().new_var(self.universe(), TypeVariableOrigin { param_def_id: None })
+ }
+
pub fn next_ty_var_with_origin(&self, origin: TypeVariableOrigin) -> Ty<'db> {
let vid = self.inner.borrow_mut().type_variables().new_var(self.universe(), origin);
Ty::new_var(self.interner, vid)
@@ -519,6 +525,15 @@ impl<'db> InferCtxt<'db> {
self.next_const_var_with_origin(ConstVariableOrigin { param_def_id: None })
}
+ pub fn next_const_vid(&self) -> ConstVid {
+ self
+ .inner
+ .borrow_mut()
+ .const_unification_table()
+ .new_key(ConstVariableValue::Unknown { origin: ConstVariableOrigin { param_def_id: None }, universe: self.universe() })
+ .vid
+ }
+
pub fn next_const_var_with_origin(&self, origin: ConstVariableOrigin) -> Const<'db> {
let vid = self
.inner
@@ -546,12 +561,20 @@ impl<'db> InferCtxt<'db> {
Ty::new_int_var(self.interner, next_int_var_id)
}
+ pub fn next_int_vid(&self) -> IntVid {
+ self.inner.borrow_mut().int_unification_table().new_key(IntVarValue::Unknown)
+ }
+
pub fn next_float_var(&self) -> Ty<'db> {
let next_float_var_id =
self.inner.borrow_mut().float_unification_table().new_key(FloatVarValue::Unknown);
Ty::new_float_var(self.interner, next_float_var_id)
}
+ pub fn next_float_vid(&self) -> FloatVid {
+ self.inner.borrow_mut().float_unification_table().new_key(FloatVarValue::Unknown)
+ }
+
/// Creates a fresh region variable with the next available index.
/// The variable will be created in the maximum universe created
/// thus far, allowing it to name any region created thus far.
@@ -559,6 +582,10 @@ impl<'db> InferCtxt<'db> {
self.next_region_var_in_universe(self.universe())
}
+ pub fn next_region_vid(&self) -> RegionVid {
+ self.inner.borrow_mut().unwrap_region_constraints().new_region_var(self.universe())
+ }
+
/// Creates a fresh region variable with the next available index
/// in the given universe; typically, you can use
/// `next_region_var` and just use the maximal universe.
@@ -782,6 +809,18 @@ impl<'db> InferCtxt<'db> {
}
}
+ pub fn resolve_int_var(&self, vid: IntVid) -> Option<Ty<'db>> {
+ let mut inner = self.inner.borrow_mut();
+ let value = inner.int_unification_table().probe_value(vid);
+ match value {
+ IntVarValue::IntType(ty) => Some(Ty::new_int(self.interner, ty)),
+ IntVarValue::UintType(ty) => Some(Ty::new_uint(self.interner, ty)),
+ IntVarValue::Unknown => {
+ None
+ }
+ }
+ }
+
/// Resolves a float var to a rigid int type, if it was constrained to one,
/// or else the root float var in the unification table.
pub fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> Ty<'db> {
@@ -795,6 +834,17 @@ impl<'db> InferCtxt<'db> {
}
}
+ pub fn resolve_float_var(&self, vid: FloatVid) -> Option<Ty<'db>> {
+ let mut inner = self.inner.borrow_mut();
+ let value = inner.float_unification_table().probe_value(vid);
+ match value {
+ FloatVarValue::Known(ty) => Some(Ty::new_float(self.interner, ty)),
+ FloatVarValue::Unknown => {
+ None
+ }
+ }
+ }
+
/// Where possible, replaces type/const variables in
/// `value` with their final value. Note that region variables
/// are unaffected. If a type/const variable has not been unified, it
diff --git a/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs b/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs
index eb42620557..8c7dfb25e0 100644
--- a/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs
@@ -46,7 +46,7 @@ impl<'db> InferCtxt<'db> {
UndoLogs::<UndoLog<'db>>::num_open_snapshots(&self.inner.borrow_mut().undo_log)
}
- fn start_snapshot(&self) -> CombinedSnapshot {
+ pub(crate) fn start_snapshot(&self) -> CombinedSnapshot {
debug!("start_snapshot()");
let mut inner = self.inner.borrow_mut();
@@ -59,7 +59,7 @@ impl<'db> InferCtxt<'db> {
}
#[instrument(skip(self, snapshot), level = "debug")]
- fn rollback_to(&self, snapshot: CombinedSnapshot) {
+ pub(crate) fn rollback_to(&self, snapshot: CombinedSnapshot) {
let CombinedSnapshot { undo_snapshot, region_constraints_snapshot, universe } = snapshot;
self.universe.set(universe);
diff --git a/crates/hir-ty/src/next_solver/mapping.rs b/crates/hir-ty/src/next_solver/mapping.rs
index dc54ee7d58..79c402ff29 100644
--- a/crates/hir-ty/src/next_solver/mapping.rs
+++ b/crates/hir-ty/src/next_solver/mapping.rs
@@ -2,8 +2,8 @@
use base_db::Crate;
use chalk_ir::{
- CanonicalVarKind, CanonicalVarKinds, ForeignDefId, InferenceVar, Substitution, TyVariableKind,
- WellFormed, fold::Shift, interner::HasInterner,
+ CanonicalVarKind, CanonicalVarKinds, FnPointer, InferenceVar, Substitution, TyVariableKind,
+ WellFormed, cast::Cast, fold::Shift, interner::HasInterner,
};
use hir_def::{
CallableDefId, ConstParamId, FunctionId, GeneralConstId, LifetimeParamId, TypeAliasId,
@@ -24,12 +24,12 @@ use salsa::{Id, plumbing::AsId};
use crate::next_solver::BoundConst;
use crate::{
- ConcreteConst, ConstScalar, ImplTraitId, Interner, MemoryMap,
+ ConstScalar, ImplTraitId, Interner, MemoryMap,
db::{
HirDatabase, InternedClosureId, InternedCoroutineId, InternedLifetimeParamId,
InternedOpaqueTyId, InternedTypeOrConstParamId,
},
- from_assoc_type_id, from_chalk_trait_id,
+ from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
mapping::ToChalk,
next_solver::{
Binder, ClauseKind, ConstBytes, TraitPredicate, UnevaluatedConst,
@@ -141,6 +141,7 @@ impl<'db> rustc_type_ir::TypeFolder<DbInterner<'db>> for BinderToEarlyBinder<'db
pub trait ChalkToNextSolver<'db, Out> {
fn to_nextsolver(&self, interner: DbInterner<'db>) -> Out;
+ fn from_nextsolver(out: Out, interner: DbInterner<'db>) -> Self;
}
impl<'db> ChalkToNextSolver<'db, Ty<'db>> for chalk_ir::Ty<Interner> {
@@ -427,6 +428,343 @@ impl<'db> ChalkToNextSolver<'db, Ty<'db>> for chalk_ir::Ty<Interner> {
},
)
}
+
+ fn from_nextsolver(out: Ty<'db>, interner: DbInterner<'db>) -> Self {
+ use crate::{Scalar, TyKind};
+ use chalk_ir::{FloatTy, IntTy, UintTy};
+ match out.kind() {
+ rustc_type_ir::TyKind::Bool => TyKind::Scalar(Scalar::Bool),
+ rustc_type_ir::TyKind::Char => TyKind::Scalar(Scalar::Char),
+ rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I8) => {
+ TyKind::Scalar(Scalar::Int(IntTy::I8))
+ }
+ rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I16) => {
+ TyKind::Scalar(Scalar::Int(IntTy::I16))
+ }
+ rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I32) => {
+ TyKind::Scalar(Scalar::Int(IntTy::I32))
+ }
+ rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I64) => {
+ TyKind::Scalar(Scalar::Int(IntTy::I64))
+ }
+ rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I128) => {
+ TyKind::Scalar(Scalar::Int(IntTy::I128))
+ }
+ rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::Isize) => {
+ TyKind::Scalar(Scalar::Int(IntTy::Isize))
+ }
+ rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U8) => {
+ TyKind::Scalar(Scalar::Uint(UintTy::U8))
+ }
+ rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U16) => {
+ TyKind::Scalar(Scalar::Uint(UintTy::U16))
+ }
+ rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U32) => {
+ TyKind::Scalar(Scalar::Uint(UintTy::U32))
+ }
+ rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U64) => {
+ TyKind::Scalar(Scalar::Uint(UintTy::U64))
+ }
+ rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U128) => {
+ TyKind::Scalar(Scalar::Uint(UintTy::U128))
+ }
+ rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::Usize) => {
+ TyKind::Scalar(Scalar::Uint(UintTy::Usize))
+ }
+ rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F16) => {
+ TyKind::Scalar(Scalar::Float(FloatTy::F16))
+ }
+ rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F32) => {
+ TyKind::Scalar(Scalar::Float(FloatTy::F32))
+ }
+ rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F64) => {
+ TyKind::Scalar(Scalar::Float(FloatTy::F64))
+ }
+ rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F128) => {
+ TyKind::Scalar(Scalar::Float(FloatTy::F128))
+ }
+ rustc_type_ir::TyKind::Str => TyKind::Str,
+ rustc_type_ir::TyKind::Error(_) => TyKind::Error,
+ rustc_type_ir::TyKind::Never => TyKind::Never,
+
+ rustc_type_ir::TyKind::Adt(def, args) => {
+ let adt_id = def.inner().id;
+ let subst = ChalkToNextSolver::from_nextsolver(args, interner);
+ TyKind::Adt(chalk_ir::AdtId(adt_id), subst)
+ }
+
+ rustc_type_ir::TyKind::Infer(infer_ty) => {
+ let (var, kind) = match infer_ty {
+ rustc_type_ir::InferTy::TyVar(var) => {
+ (InferenceVar::from(var.as_u32()), TyVariableKind::General)
+ }
+ rustc_type_ir::InferTy::IntVar(var) => {
+ (InferenceVar::from(var.as_u32()), TyVariableKind::Integer)
+ }
+ rustc_type_ir::InferTy::FloatVar(var) => {
+ (InferenceVar::from(var.as_u32()), TyVariableKind::Float)
+ }
+ _ => todo!(),
+ };
+ TyKind::InferenceVar(var, kind)
+ }
+
+ rustc_type_ir::TyKind::Ref(r, ty, mutability) => {
+ let mutability = match mutability {
+ rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut,
+ rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not,
+ };
+ let r = ChalkToNextSolver::from_nextsolver(r, interner);
+ let ty = ChalkToNextSolver::from_nextsolver(ty, interner);
+ TyKind::Ref(mutability, r, ty)
+ }
+
+ rustc_type_ir::TyKind::Tuple(tys) => {
+ let size = tys.len();
+ let subst = Substitution::from_iter(
+ Interner,
+ tys.iter().map(|ty| {
+ chalk_ir::GenericArgData::Ty(ChalkToNextSolver::from_nextsolver(
+ ty, interner,
+ ))
+ .intern(Interner)
+ }),
+ );
+ TyKind::Tuple(size, subst)
+ }
+
+ rustc_type_ir::TyKind::Array(ty, const_) => {
+ let ty = ChalkToNextSolver::from_nextsolver(ty, interner);
+ let const_ = ChalkToNextSolver::from_nextsolver(const_, interner);
+ TyKind::Array(ty, const_)
+ }
+
+ rustc_type_ir::TyKind::Alias(alias_ty_kind, alias_ty) => match alias_ty_kind {
+ rustc_type_ir::AliasTyKind::Projection => {
+ let assoc_ty_id = match alias_ty.def_id {
+ SolverDefId::TypeAliasId(id) => id,
+ _ => unreachable!(),
+ };
+ let associated_ty_id = to_assoc_type_id(assoc_ty_id);
+ let substitution = ChalkToNextSolver::from_nextsolver(alias_ty.args, interner);
+ TyKind::AssociatedType(associated_ty_id, substitution)
+ }
+ rustc_type_ir::AliasTyKind::Opaque => {
+ let opaque_ty_id = match alias_ty.def_id {
+ SolverDefId::InternedOpaqueTyId(id) => id,
+ _ => unreachable!(),
+ };
+ let substitution = ChalkToNextSolver::from_nextsolver(alias_ty.args, interner);
+ TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
+ opaque_ty_id: opaque_ty_id.into(),
+ substitution,
+ }))
+ }
+ rustc_type_ir::AliasTyKind::Inherent => todo!(),
+ rustc_type_ir::AliasTyKind::Free => todo!(),
+ },
+
+ rustc_type_ir::TyKind::Placeholder(placeholder) => {
+ let ui = chalk_ir::UniverseIndex { counter: placeholder.universe.as_usize() };
+ let placeholder_index =
+ chalk_ir::PlaceholderIndex { idx: placeholder.bound.var.as_usize(), ui };
+ TyKind::Placeholder(placeholder_index)
+ }
+
+ rustc_type_ir::TyKind::Bound(debruijn_index, ty) => {
+ TyKind::BoundVar(chalk_ir::BoundVar {
+ debruijn: chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()),
+ index: ty.var.as_usize(),
+ })
+ }
+
+ rustc_type_ir::TyKind::FnPtr(bound_sig, fn_header) => {
+ let num_binders = bound_sig.bound_vars().len();
+ let sig = chalk_ir::FnSig {
+ abi: fn_header.abi,
+ safety: match fn_header.safety {
+ crate::next_solver::abi::Safety::Safe => chalk_ir::Safety::Safe,
+ crate::next_solver::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe,
+ },
+ variadic: fn_header.c_variadic,
+ };
+ let args = GenericArgs::new_from_iter(
+ interner,
+ bound_sig.skip_binder().inputs_and_output.iter().map(|a| a.into()),
+ );
+ let substitution = ChalkToNextSolver::from_nextsolver(args, interner);
+ let substitution = chalk_ir::FnSubst(substitution);
+ let fnptr = chalk_ir::FnPointer { num_binders, sig, substitution };
+ TyKind::Function(fnptr)
+ }
+
+ rustc_type_ir::TyKind::Dynamic(preds, region, dyn_kind) => {
+ assert!(matches!(dyn_kind, rustc_type_ir::DynKind::Dyn));
+ let self_ty = Ty::new_bound(
+ interner,
+ DebruijnIndex::from_u32(1),
+ BoundTy { kind: BoundTyKind::Anon, var: BoundVar::from_u32(0) },
+ );
+ let bounds = chalk_ir::QuantifiedWhereClauses::from_iter(
+ Interner,
+ preds.iter().map(|p| {
+ let binders = chalk_ir::VariableKinds::from_iter(
+ Interner,
+ p.bound_vars().iter().map(|b| match b {
+ BoundVarKind::Ty(kind) => {
+ chalk_ir::VariableKind::Ty(TyVariableKind::General)
+ }
+ BoundVarKind::Region(kind) => chalk_ir::VariableKind::Lifetime,
+ BoundVarKind::Const => chalk_ir::VariableKind::Const(
+ crate::TyKind::Error.intern(Interner),
+ ),
+ }),
+ );
+ let where_clause = match p.skip_binder() {
+ rustc_type_ir::ExistentialPredicate::Trait(trait_ref) => {
+ let trait_ref = TraitRef::new(
+ interner,
+ trait_ref.def_id,
+ [self_ty.clone().into()]
+ .into_iter()
+ .chain(trait_ref.args.iter()),
+ );
+ let trait_id = match trait_ref.def_id {
+ SolverDefId::TraitId(id) => to_chalk_trait_id(id),
+ _ => unreachable!(),
+ };
+ let substitution =
+ ChalkToNextSolver::from_nextsolver(trait_ref.args, interner);
+ let trait_ref = chalk_ir::TraitRef { trait_id, substitution };
+ chalk_ir::WhereClause::Implemented(trait_ref)
+ }
+ rustc_type_ir::ExistentialPredicate::AutoTrait(trait_) => {
+ let trait_id = match trait_ {
+ SolverDefId::TraitId(id) => to_chalk_trait_id(id),
+ _ => unreachable!(),
+ };
+ let substitution = chalk_ir::Substitution::empty(Interner);
+ let trait_ref = chalk_ir::TraitRef { trait_id, substitution };
+ chalk_ir::WhereClause::Implemented(trait_ref)
+ }
+ rustc_type_ir::ExistentialPredicate::Projection(
+ existential_projection,
+ ) => {
+ let projection = ProjectionPredicate {
+ projection_term: AliasTerm::new(
+ interner,
+ existential_projection.def_id,
+ [self_ty.clone().into()]
+ .iter()
+ .chain(existential_projection.args.clone().iter()),
+ ),
+ term: existential_projection.term.clone(),
+ };
+ let associated_ty_id = match projection.projection_term.def_id {
+ SolverDefId::TypeAliasId(id) => to_assoc_type_id(id),
+ _ => unreachable!(),
+ };
+ let substitution = ChalkToNextSolver::from_nextsolver(
+ projection.projection_term.args,
+ interner,
+ );
+ let alias = chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
+ associated_ty_id,
+ substitution,
+ });
+ let ty = match projection.term {
+ Term::Ty(ty) => ty,
+ _ => unreachable!(),
+ };
+ let ty = ChalkToNextSolver::from_nextsolver(ty, interner);
+ let alias_eq = chalk_ir::AliasEq { alias, ty };
+ chalk_ir::WhereClause::AliasEq(alias_eq)
+ }
+ };
+ chalk_ir::Binders::new(binders, where_clause)
+ }),
+ );
+ let binders = chalk_ir::VariableKinds::from1(
+ Interner,
+ chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
+ );
+ let bounds = chalk_ir::Binders::new(binders, bounds);
+ let dyn_ty = chalk_ir::DynTy {
+ bounds,
+ lifetime: ChalkToNextSolver::from_nextsolver(region, interner),
+ };
+ TyKind::Dyn(dyn_ty)
+ }
+
+ rustc_type_ir::TyKind::Slice(ty) => {
+ let ty = ChalkToNextSolver::from_nextsolver(ty, interner);
+ TyKind::Slice(ty)
+ }
+
+ rustc_type_ir::TyKind::Foreign(def_id) => {
+ let id = match def_id {
+ SolverDefId::TypeAliasId(id) => to_foreign_def_id(id),
+ _ => unreachable!(),
+ };
+ TyKind::Foreign(id)
+ }
+ rustc_type_ir::TyKind::Pat(_, _) => todo!(),
+ rustc_type_ir::TyKind::RawPtr(ty, mutability) => {
+ let mutability = match mutability {
+ rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut,
+ rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not,
+ };
+ let ty = ChalkToNextSolver::from_nextsolver(ty, interner);
+ TyKind::Raw(mutability, ty)
+ }
+ rustc_type_ir::TyKind::FnDef(def_id, args) => {
+ let subst = ChalkToNextSolver::from_nextsolver(args, interner);
+ match def_id {
+ SolverDefId::FunctionId(id) => {
+ TyKind::FnDef(CallableDefId::FunctionId(id).to_chalk(interner.db()), subst)
+ }
+ SolverDefId::Ctor(Ctor::Enum(e)) => TyKind::FnDef(
+ CallableDefId::EnumVariantId(e).to_chalk(interner.db()),
+ subst,
+ ),
+ SolverDefId::Ctor(Ctor::Struct(s)) => {
+ TyKind::FnDef(CallableDefId::StructId(s).to_chalk(interner.db()), subst)
+ }
+ _ => unreachable!("Unexpected def id {:?}", def_id),
+ }
+ }
+
+ rustc_type_ir::TyKind::Closure(def_id, args) => {
+ let id = match def_id {
+ SolverDefId::InternedClosureId(id) => id,
+ _ => unreachable!(),
+ };
+ let subst = ChalkToNextSolver::from_nextsolver(args, interner);
+ TyKind::Closure(id.into(), subst)
+ }
+ rustc_type_ir::TyKind::CoroutineClosure(_, _) => todo!(),
+ rustc_type_ir::TyKind::Coroutine(def_id, args) => {
+ let id = match def_id {
+ SolverDefId::InternedCoroutineId(id) => id,
+ _ => unreachable!(),
+ };
+ let subst = ChalkToNextSolver::from_nextsolver(args, interner);
+ TyKind::Coroutine(id.into(), subst)
+ }
+ rustc_type_ir::TyKind::CoroutineWitness(def_id, args) => {
+ let id = match def_id {
+ SolverDefId::InternedCoroutineId(id) => id,
+ _ => unreachable!(),
+ };
+ let subst = ChalkToNextSolver::from_nextsolver(args, interner);
+ TyKind::CoroutineWitness(id.into(), subst)
+ }
+
+ rustc_type_ir::TyKind::Param(_) => todo!(),
+ rustc_type_ir::TyKind::UnsafeBinder(_) => todo!(),
+ }
+ .intern(Interner)
+ }
}
impl<'db> ChalkToNextSolver<'db, Region<'db>> for chalk_ir::Lifetime<Interner> {
@@ -461,6 +799,40 @@ impl<'db> ChalkToNextSolver<'db, Region<'db>> for chalk_ir::Lifetime<Interner> {
},
)
}
+
+ fn from_nextsolver(out: Region<'db>, interner: DbInterner<'db>) -> Self {
+ match out.kind() {
+ rustc_type_ir::RegionKind::ReEarlyParam(early) => todo!(),
+ rustc_type_ir::RegionKind::ReBound(db, bound) => chalk_ir::Lifetime::new(
+ Interner,
+ chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new(
+ chalk_ir::DebruijnIndex::new(db.as_u32()),
+ bound.var.as_usize(),
+ )),
+ ),
+ rustc_type_ir::RegionKind::ReLateParam(_) => todo!(),
+ rustc_type_ir::RegionKind::ReStatic => {
+ chalk_ir::Lifetime::new(Interner, chalk_ir::LifetimeData::Static)
+ }
+ rustc_type_ir::RegionKind::ReVar(vid) => chalk_ir::Lifetime::new(
+ Interner,
+ chalk_ir::LifetimeData::InferenceVar(chalk_ir::InferenceVar::from(vid.as_u32())),
+ ),
+ rustc_type_ir::RegionKind::RePlaceholder(placeholder) => chalk_ir::Lifetime::new(
+ Interner,
+ chalk_ir::LifetimeData::Placeholder(chalk_ir::PlaceholderIndex {
+ idx: placeholder.bound.var.as_usize(),
+ ui: chalk_ir::UniverseIndex { counter: placeholder.universe.as_usize() },
+ }),
+ ),
+ rustc_type_ir::RegionKind::ReErased => {
+ chalk_ir::Lifetime::new(Interner, chalk_ir::LifetimeData::Erased)
+ }
+ rustc_type_ir::RegionKind::ReError(_) => {
+ chalk_ir::Lifetime::new(Interner, chalk_ir::LifetimeData::Error)
+ }
+ }
+ }
}
impl<'db> ChalkToNextSolver<'db, Const<'db>> for chalk_ir::Const<Interner> {
@@ -505,6 +877,62 @@ impl<'db> ChalkToNextSolver<'db, Const<'db>> for chalk_ir::Const<Interner> {
},
)
}
+
+ fn from_nextsolver(out: Const<'db>, interner: DbInterner<'db>) -> Self {
+ let value: chalk_ir::ConstValue<Interner> = match out.kind() {
+ rustc_type_ir::ConstKind::Param(_) => unimplemented!(),
+ rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Var(var)) => {
+ chalk_ir::ConstValue::InferenceVar(chalk_ir::InferenceVar::from(var.as_u32()))
+ }
+ rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Fresh(fresh)) => {
+ panic!("Vars should not be freshened.")
+ }
+ rustc_type_ir::ConstKind::Bound(debruijn_index, var) => {
+ chalk_ir::ConstValue::BoundVar(chalk_ir::BoundVar::new(
+ chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()),
+ var.index(),
+ ))
+ }
+ rustc_type_ir::ConstKind::Placeholder(placeholder_const) => {
+ chalk_ir::ConstValue::Placeholder(chalk_ir::PlaceholderIndex {
+ ui: chalk_ir::UniverseIndex { counter: placeholder_const.universe.as_usize() },
+ idx: placeholder_const.bound.as_usize(),
+ })
+ }
+ rustc_type_ir::ConstKind::Unevaluated(unevaluated_const) => {
+ let id = match unevaluated_const.def {
+ SolverDefId::ConstId(id) => GeneralConstId::ConstId(id),
+ SolverDefId::StaticId(id) => GeneralConstId::StaticId(id),
+ _ => unreachable!(),
+ };
+ let subst = ChalkToNextSolver::from_nextsolver(unevaluated_const.args, interner);
+ chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
+ interned: ConstScalar::UnevaluatedConst(id, subst),
+ })
+ }
+ rustc_type_ir::ConstKind::Value(value_const) => {
+ let bytes = value_const.value.inner();
+ let value = chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
+ // SAFETY: will never use this without a db
+ interned: ConstScalar::Bytes(bytes.0.clone(), unsafe {
+ std::mem::transmute::<MemoryMap<'_>, MemoryMap<'static>>(bytes.1.clone())
+ }),
+ });
+ return chalk_ir::ConstData {
+ ty: ChalkToNextSolver::from_nextsolver(value_const.ty, interner),
+ value,
+ }
+ .intern(Interner);
+ }
+ rustc_type_ir::ConstKind::Error(_) => {
+ chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
+ interned: ConstScalar::Unknown,
+ })
+ }
+ rustc_type_ir::ConstKind::Expr(_) => unimplemented!(),
+ };
+ chalk_ir::ConstData { ty: crate::TyKind::Error.intern(Interner), value }.intern(Interner)
+ }
}
impl<'db> ChalkToNextSolver<'db, rustc_type_ir::FnSigTys<DbInterner<'db>>>
@@ -518,6 +946,13 @@ impl<'db> ChalkToNextSolver<'db, rustc_type_ir::FnSigTys<DbInterner<'db>>>
),
}
}
+
+ fn from_nextsolver(
+ out: rustc_type_ir::FnSigTys<DbInterner<'db>>,
+ interner: DbInterner<'db>,
+ ) -> Self {
+ todo!()
+ }
}
impl<
@@ -536,6 +971,13 @@ impl<
binders.to_nextsolver(interner),
)
}
+
+ fn from_nextsolver(
+ out: rustc_type_ir::Binder<DbInterner<'db>, U>,
+ interner: DbInterner<'db>,
+ ) -> Self {
+ todo!()
+ }
}
impl<'db> ChalkToNextSolver<'db, BoundVarKinds> for chalk_ir::VariableKinds<Interner> {
@@ -545,6 +987,10 @@ impl<'db> ChalkToNextSolver<'db, BoundVarKinds> for chalk_ir::VariableKinds<Inte
self.iter(Interner).map(|v| v.to_nextsolver(interner)),
)
}
+
+ fn from_nextsolver(out: BoundVarKinds, interner: DbInterner<'db>) -> Self {
+ todo!()
+ }
}
impl<'db> ChalkToNextSolver<'db, BoundVarKind> for chalk_ir::VariableKind<Interner> {
@@ -555,6 +1001,10 @@ impl<'db> ChalkToNextSolver<'db, BoundVarKind> for chalk_ir::VariableKind<Intern
chalk_ir::VariableKind::Const(_ty) => BoundVarKind::Const,
}
}
+
+ fn from_nextsolver(out: BoundVarKind, interner: DbInterner<'db>) -> Self {
+ todo!()
+ }
}
impl<'db> ChalkToNextSolver<'db, GenericArg<'db>> for chalk_ir::GenericArg<Interner> {
@@ -565,6 +1015,10 @@ impl<'db> ChalkToNextSolver<'db, GenericArg<'db>> for chalk_ir::GenericArg<Inter
chalk_ir::GenericArgData::Const(const_) => const_.to_nextsolver(interner).into(),
}
}
+
+ fn from_nextsolver(out: GenericArg<'db>, interner: DbInterner<'db>) -> Self {
+ todo!()
+ }
}
impl<'db> ChalkToNextSolver<'db, GenericArgs<'db>> for chalk_ir::Substitution<Interner> {
fn to_nextsolver(&self, interner: DbInterner<'db>) -> GenericArgs<'db> {
@@ -573,6 +1027,31 @@ impl<'db> ChalkToNextSolver<'db, GenericArgs<'db>> for chalk_ir::Substitution<In
self.iter(Interner).map(|arg| -> GenericArg<'db> { arg.to_nextsolver(interner) }),
)
}
+
+ fn from_nextsolver(out: GenericArgs<'db>, interner: DbInterner<'db>) -> Self {
+ let mut substs = Vec::with_capacity(out.len());
+ for arg in out.iter() {
+ match arg.clone().kind() {
+ rustc_type_ir::GenericArgKind::Type(ty) => {
+ let ty = ChalkToNextSolver::from_nextsolver(ty, interner);
+ substs.push(chalk_ir::GenericArgData::Ty(ty).intern(Interner));
+ }
+ rustc_type_ir::GenericArgKind::Lifetime(region) => {
+ let lifetime = ChalkToNextSolver::from_nextsolver(region, interner);
+ substs.push(chalk_ir::GenericArgData::Lifetime(lifetime).intern(Interner));
+ }
+ rustc_type_ir::GenericArgKind::Const(const_) => {
+ substs.push(
+ chalk_ir::GenericArgData::Const(ChalkToNextSolver::from_nextsolver(
+ const_, interner,
+ ))
+ .intern(Interner),
+ );
+ }
+ }
+ }
+ Substitution::from_iter(Interner, substs)
+ }
}
impl<'db> ChalkToNextSolver<'db, Tys<'db>> for chalk_ir::Substitution<Interner> {
@@ -588,18 +1067,30 @@ impl<'db> ChalkToNextSolver<'db, Tys<'db>> for chalk_ir::Substitution<Interner>
}),
)
}
+
+ fn from_nextsolver(out: Tys<'db>, interner: DbInterner<'db>) -> Self {
+ todo!()
+ }
}
impl<'db> ChalkToNextSolver<'db, rustc_type_ir::DebruijnIndex> for chalk_ir::DebruijnIndex {
fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::DebruijnIndex {
rustc_type_ir::DebruijnIndex::from_u32(self.depth())
}
+
+ fn from_nextsolver(out: rustc_type_ir::DebruijnIndex, interner: DbInterner<'db>) -> Self {
+ todo!()
+ }
}
impl<'db> ChalkToNextSolver<'db, rustc_type_ir::UniverseIndex> for chalk_ir::UniverseIndex {
fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::UniverseIndex {
rustc_type_ir::UniverseIndex::from_u32(self.counter as u32)
}
+
+ fn from_nextsolver(out: rustc_type_ir::UniverseIndex, interner: DbInterner<'db>) -> Self {
+ todo!()
+ }
}
impl<'db> ChalkToNextSolver<'db, rustc_type_ir::InferTy>
@@ -618,6 +1109,10 @@ impl<'db> ChalkToNextSolver<'db, rustc_type_ir::InferTy>
}
}
}
+
+ fn from_nextsolver(out: rustc_type_ir::InferTy, interner: DbInterner<'db>) -> Self {
+ todo!()
+ }
}
impl<'db> ChalkToNextSolver<'db, rustc_ast_ir::Mutability> for chalk_ir::Mutability {
@@ -627,6 +1122,10 @@ impl<'db> ChalkToNextSolver<'db, rustc_ast_ir::Mutability> for chalk_ir::Mutabil
chalk_ir::Mutability::Not => rustc_ast_ir::Mutability::Not,
}
}
+
+ fn from_nextsolver(out: rustc_ast_ir::Mutability, interner: DbInterner<'db>) -> Self {
+ todo!()
+ }
}
impl<'db> ChalkToNextSolver<'db, rustc_type_ir::Variance> for crate::Variance {
@@ -638,16 +1137,65 @@ impl<'db> ChalkToNextSolver<'db, rustc_type_ir::Variance> for crate::Variance {
crate::Variance::Bivariant => rustc_type_ir::Variance::Bivariant,
}
}
+
+ fn from_nextsolver(out: rustc_type_ir::Variance, interner: DbInterner<'db>) -> Self {
+ todo!()
+ }
}
-impl<'db> ChalkToNextSolver<'db, Canonical<'db, Goal<DbInterner<'db>, Predicate<'db>>>>
- for chalk_ir::Canonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>
+impl<'db> ChalkToNextSolver<'db, rustc_type_ir::Variance> for chalk_ir::Variance {
+ fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::Variance {
+ match self {
+ chalk_ir::Variance::Covariant => rustc_type_ir::Variance::Covariant,
+ chalk_ir::Variance::Invariant => rustc_type_ir::Variance::Invariant,
+ chalk_ir::Variance::Contravariant => rustc_type_ir::Variance::Contravariant,
+ }
+ }
+
+ fn from_nextsolver(out: rustc_type_ir::Variance, interner: DbInterner<'db>) -> Self {
+ todo!()
+ }
+}
+
+impl<'db> ChalkToNextSolver<'db, VariancesOf> for chalk_ir::Variances<Interner> {
+ fn to_nextsolver(&self, interner: DbInterner<'db>) -> VariancesOf {
+ VariancesOf::new_from_iter(
+ interner,
+ self.as_slice(Interner).iter().map(|v| v.to_nextsolver(interner)),
+ )
+ }
+
+ fn from_nextsolver(out: VariancesOf, interner: DbInterner<'db>) -> Self {
+ todo!()
+ }
+}
+
+impl<'db> ChalkToNextSolver<'db, Goal<DbInterner<'db>, Predicate<'db>>>
+ for chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>
{
- fn to_nextsolver(
- &self,
+ fn to_nextsolver(&self, interner: DbInterner<'db>) -> Goal<DbInterner<'db>, Predicate<'db>> {
+ Goal::new(
+ interner,
+ self.environment.to_nextsolver(interner),
+ self.goal.to_nextsolver(interner),
+ )
+ }
+
+ fn from_nextsolver(
+ out: Goal<DbInterner<'db>, Predicate<'db>>,
interner: DbInterner<'db>,
- ) -> Canonical<'db, Goal<DbInterner<'db>, Predicate<'db>>> {
- let param_env = self.value.environment.to_nextsolver(interner);
+ ) -> Self {
+ chalk_ir::InEnvironment {
+ environment: ChalkToNextSolver::from_nextsolver(out.param_env, interner),
+ goal: ChalkToNextSolver::from_nextsolver(out.predicate, interner),
+ }
+ }
+}
+
+impl<'db, T: HasInterner<Interner = Interner> + ChalkToNextSolver<'db, U>, U>
+ ChalkToNextSolver<'db, Canonical<'db, U>> for chalk_ir::Canonical<T>
+{
+ fn to_nextsolver(&self, interner: DbInterner<'db>) -> Canonical<'db, U> {
let variables = CanonicalVars::new_from_iter(
interner,
self.binders.iter(Interner).map(|k| match &k.kind {
@@ -672,10 +1220,49 @@ impl<'db> ChalkToNextSolver<'db, Canonical<'db, Goal<DbInterner<'db>, Predicate<
);
Canonical {
max_universe: UniverseIndex::ROOT,
- value: Goal::new(interner, param_env, self.value.goal.to_nextsolver(interner)),
+ value: self.value.to_nextsolver(interner),
variables,
}
}
+
+ fn from_nextsolver(out: Canonical<'db, U>, interner: DbInterner<'db>) -> Self {
+ let binders = chalk_ir::CanonicalVarKinds::from_iter(
+ Interner,
+ out.variables.iter().map(|v| match v {
+ rustc_type_ir::CanonicalVarKind::Ty(
+ rustc_type_ir::CanonicalTyVarKind::General(ui),
+ ) => chalk_ir::CanonicalVarKind::new(
+ chalk_ir::VariableKind::Ty(TyVariableKind::General),
+ chalk_ir::UniverseIndex { counter: ui.as_usize() },
+ ),
+ rustc_type_ir::CanonicalVarKind::Ty(rustc_type_ir::CanonicalTyVarKind::Int) => {
+ chalk_ir::CanonicalVarKind::new(
+ chalk_ir::VariableKind::Ty(TyVariableKind::Integer),
+ chalk_ir::UniverseIndex::root(),
+ )
+ }
+ rustc_type_ir::CanonicalVarKind::Ty(rustc_type_ir::CanonicalTyVarKind::Float) => {
+ chalk_ir::CanonicalVarKind::new(
+ chalk_ir::VariableKind::Ty(TyVariableKind::Float),
+ chalk_ir::UniverseIndex::root(),
+ )
+ }
+ rustc_type_ir::CanonicalVarKind::PlaceholderTy(_) => todo!(),
+ rustc_type_ir::CanonicalVarKind::Region(ui) => chalk_ir::CanonicalVarKind::new(
+ chalk_ir::VariableKind::Lifetime,
+ chalk_ir::UniverseIndex { counter: ui.as_usize() },
+ ),
+ rustc_type_ir::CanonicalVarKind::PlaceholderRegion(_) => todo!(),
+ rustc_type_ir::CanonicalVarKind::Const(ui) => chalk_ir::CanonicalVarKind::new(
+ chalk_ir::VariableKind::Const(chalk_ir::TyKind::Error.intern(Interner)),
+ chalk_ir::UniverseIndex { counter: ui.as_usize() },
+ ),
+ rustc_type_ir::CanonicalVarKind::PlaceholderConst(_) => todo!(),
+ }),
+ );
+ let value = ChalkToNextSolver::from_nextsolver(out.value, interner);
+ chalk_ir::Canonical { binders, value }
+ }
}
impl<'db> ChalkToNextSolver<'db, Predicate<'db>> for chalk_ir::Goal<Interner> {
@@ -693,7 +1280,16 @@ impl<'db> ChalkToNextSolver<'db, Predicate<'db>> for chalk_ir::Goal<Interner> {
}
chalk_ir::GoalData::All(goals) => panic!("Should not be constructed."),
chalk_ir::GoalData::Not(goal) => panic!("Should not be constructed."),
- chalk_ir::GoalData::EqGoal(eq_goal) => panic!("Should not be constructed."),
+ chalk_ir::GoalData::EqGoal(eq_goal) => {
+ let pred_kind = PredicateKind::AliasRelate(
+ Term::Ty(eq_goal.a.assert_ty_ref(Interner).clone().to_nextsolver(interner)),
+ Term::Ty(eq_goal.b.assert_ty_ref(Interner).clone().to_nextsolver(interner)),
+ rustc_type_ir::AliasRelationDirection::Equate,
+ );
+ let pred_kind =
+ Binder::bind_with_vars(pred_kind, BoundVarKinds::new_from_iter(interner, []));
+ Predicate::new(interner, pred_kind)
+ }
chalk_ir::GoalData::SubtypeGoal(subtype_goal) => {
let subtype_predicate = SubtypePredicate {
a: subtype_goal.a.to_nextsolver(interner),
@@ -718,6 +1314,124 @@ impl<'db> ChalkToNextSolver<'db, Predicate<'db>> for chalk_ir::Goal<Interner> {
chalk_ir::GoalData::CannotProve => panic!("Should not be constructed."),
}
}
+
+ fn from_nextsolver(out: Predicate<'db>, interner: DbInterner<'db>) -> Self {
+ chalk_ir::Goal::new(
+ Interner,
+ match out.kind().skip_binder() {
+ rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait(
+ trait_pred,
+ )) => {
+ let trait_ref =
+ ChalkToNextSolver::from_nextsolver(trait_pred.trait_ref, interner);
+ let where_clause = chalk_ir::WhereClause::Implemented(trait_ref);
+ chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause))
+ }
+ rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Projection(
+ proj_predicate,
+ )) => {
+ let associated_ty_id = match proj_predicate.def_id() {
+ SolverDefId::TypeAliasId(id) => to_assoc_type_id(id),
+ _ => unreachable!(),
+ };
+ let substitution = ChalkToNextSolver::from_nextsolver(
+ proj_predicate.projection_term.args,
+ interner,
+ );
+ let alias = chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
+ associated_ty_id,
+ substitution,
+ });
+ let ty = match proj_predicate.term.kind() {
+ rustc_type_ir::TermKind::Ty(ty) => ty,
+ rustc_type_ir::TermKind::Const(_) => todo!(),
+ };
+ let ty = ChalkToNextSolver::from_nextsolver(ty, interner);
+ let alias_eq = chalk_ir::AliasEq { alias, ty };
+ let where_clause = chalk_ir::WhereClause::AliasEq(alias_eq);
+ chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause))
+ }
+ rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::TypeOutlives(
+ outlives,
+ )) => {
+ let lifetime = ChalkToNextSolver::from_nextsolver(outlives.1, interner);
+ let ty = ChalkToNextSolver::from_nextsolver(outlives.0, interner);
+ let where_clause =
+ chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives {
+ lifetime,
+ ty,
+ });
+ chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause))
+ }
+ rustc_type_ir::PredicateKind::Clause(
+ rustc_type_ir::ClauseKind::RegionOutlives(outlives),
+ ) => {
+ let a = ChalkToNextSolver::from_nextsolver(outlives.0, interner);
+ let b = ChalkToNextSolver::from_nextsolver(outlives.1, interner);
+ let where_clause =
+ chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives {
+ a,
+ b,
+ });
+ chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause))
+ }
+ rustc_type_ir::PredicateKind::Clause(_) => todo!(),
+ rustc_type_ir::PredicateKind::DynCompatible(_) => todo!(),
+ rustc_type_ir::PredicateKind::Subtype(subtype_predicate) => todo!(),
+ rustc_type_ir::PredicateKind::Coerce(coerce_predicate) => todo!(),
+ rustc_type_ir::PredicateKind::ConstEquate(_, _) => todo!(),
+ rustc_type_ir::PredicateKind::Ambiguous => todo!(),
+ rustc_type_ir::PredicateKind::NormalizesTo(normalizes_to) => todo!(),
+ rustc_type_ir::PredicateKind::AliasRelate(
+ alias_term,
+ ty_term,
+ alias_relation_direction,
+ ) => {
+ let ty = match ty_term {
+ Term::Ty(ty) => ChalkToNextSolver::from_nextsolver(ty, interner),
+ Term::Const(..) => todo!(),
+ };
+ match alias_term {
+ Term::Ty(alias_ty) => match alias_ty.kind() {
+ rustc_type_ir::TyKind::Alias(kind, alias) => match kind {
+ rustc_type_ir::AliasTyKind::Projection => {
+ let associated_ty_id = match alias.def_id {
+ SolverDefId::TypeAliasId(id) => to_assoc_type_id(id),
+ _ => todo!(),
+ };
+ let substitution =
+ ChalkToNextSolver::from_nextsolver(alias.args, interner);
+ let proj_ty =
+ chalk_ir::ProjectionTy { associated_ty_id, substitution };
+ let alias = chalk_ir::AliasTy::Projection(proj_ty);
+ let alias_eq = chalk_ir::AliasEq { alias, ty };
+ chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(
+ chalk_ir::WhereClause::AliasEq(alias_eq),
+ ))
+ }
+ _ => todo!(),
+ },
+ rustc_type_ir::TyKind::Infer(var) => {
+ assert!(matches!(
+ alias_relation_direction,
+ rustc_type_ir::AliasRelationDirection::Equate
+ ));
+ let a: chalk_ir::Ty<_> =
+ ChalkToNextSolver::from_nextsolver(alias_ty, interner);
+ let eq_goal = chalk_ir::EqGoal {
+ a: chalk_ir::GenericArgData::Ty(a).intern(Interner),
+ b: chalk_ir::GenericArgData::Ty(ty).intern(Interner),
+ };
+ chalk_ir::GoalData::EqGoal(eq_goal)
+ }
+ _ => todo!("Unexpected alias term {:?}", alias_term),
+ },
+ Term::Const(..) => todo!(),
+ }
+ }
+ },
+ )
+ }
}
impl<'db> ChalkToNextSolver<'db, ParamEnv<'db>> for chalk_ir::Environment<Interner> {
@@ -730,12 +1444,32 @@ impl<'db> ChalkToNextSolver<'db, ParamEnv<'db>> for chalk_ir::Environment<Intern
Clauses::new_from_iter(interner, elaborate::elaborate(interner, clauses.iter()));
ParamEnv { clauses }
}
+
+ fn from_nextsolver(out: ParamEnv<'db>, interner: DbInterner<'db>) -> Self {
+ let clauses = chalk_ir::ProgramClauses::from_iter(
+ Interner,
+ out.clauses.iter().map(|c| -> chalk_ir::ProgramClause<Interner> {
+ ChalkToNextSolver::from_nextsolver(c, interner)
+ }),
+ );
+ chalk_ir::Environment { clauses }
+ }
}
impl<'db> ChalkToNextSolver<'db, Clause<'db>> for chalk_ir::ProgramClause<Interner> {
fn to_nextsolver(&self, interner: DbInterner<'db>) -> Clause<'db> {
Clause(Predicate::new(interner, self.data(Interner).0.to_nextsolver(interner)))
}
+
+ fn from_nextsolver(out: Clause<'db>, interner: DbInterner<'db>) -> Self {
+ chalk_ir::ProgramClause::new(
+ Interner,
+ chalk_ir::ProgramClauseData(chalk_ir::Binders::empty(
+ Interner,
+ ChalkToNextSolver::from_nextsolver(out.0.kind().skip_binder(), interner),
+ )),
+ )
+ }
}
impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>>
@@ -746,6 +1480,14 @@ impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>>
assert!(self.constraints.is_empty(Interner));
self.consequence.to_nextsolver(interner)
}
+ fn from_nextsolver(out: PredicateKind<'db>, interner: DbInterner<'db>) -> Self {
+ chalk_ir::ProgramClauseImplication {
+ consequence: ChalkToNextSolver::from_nextsolver(out, interner),
+ conditions: chalk_ir::Goals::empty(Interner),
+ constraints: chalk_ir::Constraints::empty(Interner),
+ priority: chalk_ir::ClausePriority::High,
+ }
+ }
}
impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::DomainGoal<Interner> {
@@ -864,6 +1606,98 @@ impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::DomainGoal<In
chalk_ir::DomainGoal::ObjectSafe(trait_id) => panic!("Should not be constructed."),
}
}
+
+ fn from_nextsolver(out: PredicateKind<'db>, interner: DbInterner<'db>) -> Self {
+ let domain_goal = match out {
+ rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait(trait_pred)) => {
+ let trait_ref = ChalkToNextSolver::from_nextsolver(trait_pred.trait_ref, interner);
+ let where_clause = chalk_ir::WhereClause::Implemented(trait_ref);
+ chalk_ir::DomainGoal::Holds(where_clause)
+ }
+ rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Projection(
+ proj_predicate,
+ )) => {
+ let associated_ty_id = match proj_predicate.def_id() {
+ SolverDefId::TypeAliasId(id) => to_assoc_type_id(id),
+ _ => unreachable!(),
+ };
+ let substitution = ChalkToNextSolver::from_nextsolver(
+ proj_predicate.projection_term.args,
+ interner,
+ );
+ let alias = chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
+ associated_ty_id,
+ substitution,
+ });
+ let ty = match proj_predicate.term.kind() {
+ rustc_type_ir::TermKind::Ty(ty) => ty,
+ rustc_type_ir::TermKind::Const(_) => todo!(),
+ };
+ let ty = ChalkToNextSolver::from_nextsolver(ty, interner);
+ let alias_eq = chalk_ir::AliasEq { alias, ty };
+ let where_clause = chalk_ir::WhereClause::AliasEq(alias_eq);
+ chalk_ir::DomainGoal::Holds(where_clause)
+ }
+ rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::TypeOutlives(
+ outlives,
+ )) => {
+ let lifetime = ChalkToNextSolver::from_nextsolver(outlives.1, interner);
+ let ty = ChalkToNextSolver::from_nextsolver(outlives.0, interner);
+ let where_clause =
+ chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { lifetime, ty });
+ chalk_ir::DomainGoal::Holds(where_clause)
+ }
+ rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::RegionOutlives(
+ outlives,
+ )) => {
+ let a = ChalkToNextSolver::from_nextsolver(outlives.0, interner);
+ let b = ChalkToNextSolver::from_nextsolver(outlives.1, interner);
+ let where_clause =
+ chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { a, b });
+ chalk_ir::DomainGoal::Holds(where_clause)
+ }
+ rustc_type_ir::PredicateKind::Clause(_) => todo!(),
+ rustc_type_ir::PredicateKind::DynCompatible(_) => todo!(),
+ rustc_type_ir::PredicateKind::Subtype(subtype_predicate) => todo!(),
+ rustc_type_ir::PredicateKind::Coerce(coerce_predicate) => todo!(),
+ rustc_type_ir::PredicateKind::ConstEquate(_, _) => todo!(),
+ rustc_type_ir::PredicateKind::Ambiguous => todo!(),
+ rustc_type_ir::PredicateKind::NormalizesTo(normalizes_to) => todo!(),
+ rustc_type_ir::PredicateKind::AliasRelate(
+ alias_term,
+ ty_term,
+ alias_relation_direction,
+ ) => {
+ let alias = match alias_term {
+ Term::Ty(alias_ty) => match alias_ty.kind() {
+ rustc_type_ir::TyKind::Alias(kind, alias) => match kind {
+ rustc_type_ir::AliasTyKind::Projection => {
+ let associated_ty_id = match alias.def_id {
+ SolverDefId::TypeAliasId(id) => to_assoc_type_id(id),
+ _ => todo!(),
+ };
+ let substitution =
+ ChalkToNextSolver::from_nextsolver(alias.args, interner);
+ let proj_ty =
+ chalk_ir::ProjectionTy { associated_ty_id, substitution };
+ chalk_ir::AliasTy::Projection(proj_ty)
+ }
+ _ => todo!(),
+ },
+ _ => todo!(),
+ },
+ Term::Const(..) => todo!(),
+ };
+ let ty = match ty_term {
+ Term::Ty(ty) => ChalkToNextSolver::from_nextsolver(ty, interner),
+ Term::Const(..) => todo!(),
+ };
+ let alias_eq = chalk_ir::AliasEq { alias, ty };
+ chalk_ir::DomainGoal::Holds(chalk_ir::WhereClause::AliasEq(alias_eq))
+ }
+ };
+ domain_goal
+ }
}
impl<'db> ChalkToNextSolver<'db, TraitRef<'db>> for chalk_ir::TraitRef<Interner> {
@@ -871,6 +1705,15 @@ impl<'db> ChalkToNextSolver<'db, TraitRef<'db>> for chalk_ir::TraitRef<Interner>
let args = self.substitution.to_nextsolver(interner);
TraitRef::new_from_args(interner, from_chalk_trait_id(self.trait_id).into(), args)
}
+
+ fn from_nextsolver(out: TraitRef<'db>, interner: DbInterner<'db>) -> Self {
+ let trait_id = match out.def_id {
+ SolverDefId::TraitId(id) => to_chalk_trait_id(id),
+ _ => unreachable!(),
+ };
+ let substitution = ChalkToNextSolver::from_nextsolver(out.args, interner);
+ chalk_ir::TraitRef { trait_id, substitution }
+ }
}
impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::WhereClause<Interner> {
@@ -911,6 +1754,10 @@ impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::WhereClause<I
}
}
}
+
+ fn from_nextsolver(out: PredicateKind<'db>, interner: DbInterner<'db>) -> Self {
+ todo!()
+ }
}
pub fn convert_canonical_args_for_result<'db>(
@@ -956,7 +1803,10 @@ pub fn convert_canonical_args_for_result<'db>(
binders,
value: chalk_ir::ConstrainedSubst {
constraints: chalk_ir::Constraints::empty(Interner),
- subst: convert_args_for_result(interner, &value),
+ subst: ChalkToNextSolver::from_nextsolver(
+ GenericArgs::new_from_iter(interner, value),
+ interner,
+ ),
},
}
}
@@ -1047,7 +1897,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>)
rustc_type_ir::TyKind::Adt(def, args) => {
let adt_id = def.inner().id;
- let subst = convert_args_for_result(interner, args.as_slice());
+ let subst = ChalkToNextSolver::from_nextsolver(args, interner);
TyKind::Adt(chalk_ir::AdtId(adt_id), subst)
}
@@ -1062,11 +1912,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>)
rustc_type_ir::InferTy::FloatVar(var) => {
(InferenceVar::from(var.as_u32()), TyVariableKind::Float)
}
- rustc_type_ir::InferTy::FreshFloatTy(..)
- | rustc_type_ir::InferTy::FreshIntTy(..)
- | rustc_type_ir::InferTy::FreshTy(..) => {
- panic!("Freshening shouldn't happen.")
- }
+ _ => todo!(),
};
TyKind::InferenceVar(var, kind)
}
@@ -1086,7 +1932,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>)
let subst = Substitution::from_iter(
Interner,
tys.iter().map(|ty| {
- chalk_ir::GenericArgData::Ty(convert_ty_for_result(interner, ty))
+ chalk_ir::GenericArgData::Ty(ChalkToNextSolver::from_nextsolver(ty, interner))
.intern(Interner)
}),
);
@@ -1094,8 +1940,8 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>)
}
rustc_type_ir::TyKind::Array(ty, const_) => {
- let ty = convert_ty_for_result(interner, ty);
- let const_ = convert_const_for_result(interner, const_);
+ let ty = ChalkToNextSolver::from_nextsolver(ty, interner);
+ let const_ = ChalkToNextSolver::from_nextsolver(const_, interner);
TyKind::Array(ty, const_)
}
@@ -1106,7 +1952,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>)
_ => unreachable!(),
};
let associated_ty_id = to_assoc_type_id(assoc_ty_id);
- let substitution = convert_args_for_result(interner, alias_ty.args.as_slice());
+ let substitution = ChalkToNextSolver::from_nextsolver(alias_ty.args, interner);
TyKind::AssociatedType(associated_ty_id, substitution)
}
rustc_type_ir::AliasTyKind::Opaque => {
@@ -1114,14 +1960,14 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>)
SolverDefId::InternedOpaqueTyId(id) => id,
_ => unreachable!(),
};
- let substitution = convert_args_for_result(interner, alias_ty.args.as_slice());
+ let substitution = ChalkToNextSolver::from_nextsolver(alias_ty.args, interner);
TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
opaque_ty_id: opaque_ty_id.into(),
substitution,
}))
}
- rustc_type_ir::AliasTyKind::Inherent => unimplemented!(),
- rustc_type_ir::AliasTyKind::Free => unimplemented!(),
+ rustc_type_ir::AliasTyKind::Inherent => todo!(),
+ rustc_type_ir::AliasTyKind::Free => todo!(),
},
// For `Placeholder`, `Bound` and `Param`, see the comment on the reverse conversion.
@@ -1156,7 +2002,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>)
interner,
bound_sig.skip_binder().inputs_and_output.iter().map(|a| a.into()),
);
- let substitution = convert_args_for_result(interner, args.as_slice());
+ let substitution = ChalkToNextSolver::from_nextsolver(args, interner);
let substitution = chalk_ir::FnSubst(substitution);
let fnptr = chalk_ir::FnPointer { num_binders, sig, substitution };
TyKind::Function(fnptr)
@@ -1199,11 +2045,11 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>)
let trait_ref = TraitRef::new(
interner,
trait_ref.def_id,
- [self_ty.into()].into_iter().chain(trait_ref.args.iter()),
+ [self_ty.clone().into()].into_iter().chain(trait_ref.args.iter()),
);
let trait_id = to_chalk_trait_id(trait_ref.def_id.0);
let substitution =
- convert_args_for_result(interner, trait_ref.args.as_slice());
+ ChalkToNextSolver::from_nextsolver(trait_ref.args, interner);
let trait_ref = chalk_ir::TraitRef { trait_id, substitution };
chalk_ir::WhereClause::Implemented(trait_ref)
}
@@ -1221,19 +2067,19 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>)
projection_term: AliasTerm::new(
interner,
existential_projection.def_id,
- [self_ty.into()]
+ [self_ty.clone().into()]
.iter()
- .chain(existential_projection.args.iter()),
+ .chain(existential_projection.args.clone().iter()),
),
- term: existential_projection.term,
+ term: existential_projection.term.clone(),
};
let associated_ty_id = match projection.projection_term.def_id {
SolverDefId::TypeAliasId(id) => to_assoc_type_id(id),
_ => unreachable!(),
};
- let substitution = convert_args_for_result(
+ let substitution = ChalkToNextSolver::from_nextsolver(
+ projection.projection_term.args,
interner,
- projection.projection_term.args.as_slice(),
);
let alias = chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
associated_ty_id,
@@ -1243,7 +2089,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>)
Term::Ty(ty) => ty,
_ => unreachable!(),
};
- let ty = convert_ty_for_result(interner, ty);
+ let ty = ChalkToNextSolver::from_nextsolver(ty, interner);
let alias_eq = chalk_ir::AliasEq { alias, ty };
chalk_ir::WhereClause::AliasEq(alias_eq)
}
@@ -1262,7 +2108,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>)
}
rustc_type_ir::TyKind::Slice(ty) => {
- let ty = convert_ty_for_result(interner, ty);
+ let ty = ChalkToNextSolver::from_nextsolver(ty, interner);
TyKind::Slice(ty)
}
@@ -1273,24 +2119,29 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>)
};
TyKind::Foreign(to_foreign_def_id(def_id))
}
- rustc_type_ir::TyKind::Pat(_, _) => unimplemented!(),
+ rustc_type_ir::TyKind::Pat(_, _) => todo!(),
rustc_type_ir::TyKind::RawPtr(ty, mutability) => {
let mutability = match mutability {
rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut,
rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not,
};
- let ty = convert_ty_for_result(interner, ty);
+ let ty = ChalkToNextSolver::from_nextsolver(ty, interner);
TyKind::Raw(mutability, ty)
}
rustc_type_ir::TyKind::FnDef(def_id, args) => {
- let id = match def_id {
- SolverDefId::FunctionId(id) => CallableDefId::FunctionId(id),
- SolverDefId::Ctor(Ctor::Struct(id)) => CallableDefId::StructId(id),
- SolverDefId::Ctor(Ctor::Enum(id)) => CallableDefId::EnumVariantId(id),
- _ => unreachable!(),
- };
- let subst = convert_args_for_result(interner, args.as_slice());
- TyKind::FnDef(id.to_chalk(interner.db()), subst)
+ let subst = ChalkToNextSolver::from_nextsolver(args, interner);
+ match def_id {
+ SolverDefId::FunctionId(id) => {
+ TyKind::FnDef(CallableDefId::FunctionId(id).to_chalk(interner.db()), subst)
+ }
+ SolverDefId::Ctor(Ctor::Enum(e)) => {
+ TyKind::FnDef(CallableDefId::EnumVariantId(e).to_chalk(interner.db()), subst)
+ }
+ SolverDefId::Ctor(Ctor::Struct(s)) => {
+ TyKind::FnDef(CallableDefId::StructId(s).to_chalk(interner.db()), subst)
+ }
+ _ => unreachable!("Unexpected def id {:?}", def_id),
+ }
}
rustc_type_ir::TyKind::Closure(def_id, args) => {
@@ -1298,16 +2149,16 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>)
SolverDefId::InternedClosureId(id) => id,
_ => unreachable!(),
};
- let subst = convert_args_for_result(interner, args.as_slice());
+ let subst = ChalkToNextSolver::from_nextsolver(args, interner);
TyKind::Closure(id.into(), subst)
}
- rustc_type_ir::TyKind::CoroutineClosure(_, _) => unimplemented!(),
+ rustc_type_ir::TyKind::CoroutineClosure(_, _) => todo!(),
rustc_type_ir::TyKind::Coroutine(def_id, args) => {
let id = match def_id {
SolverDefId::InternedCoroutineId(id) => id,
_ => unreachable!(),
};
- let subst = convert_args_for_result(interner, args.as_slice());
+ let subst = ChalkToNextSolver::from_nextsolver(args, interner);
TyKind::Coroutine(id.into(), subst)
}
rustc_type_ir::TyKind::CoroutineWitness(def_id, args) => {
@@ -1315,7 +2166,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>)
SolverDefId::InternedCoroutineId(id) => id,
_ => unreachable!(),
};
- let subst = convert_args_for_result(interner, args.as_slice());
+ let subst = ChalkToNextSolver::from_nextsolver(args, interner);
TyKind::CoroutineWitness(id.into(), subst)
}
@@ -1419,3 +2270,17 @@ pub fn convert_region_for_result<'db>(
};
chalk_ir::Lifetime::new(Interner, lifetime)
}
+
+pub trait InferenceVarExt {
+ fn to_vid(self) -> rustc_type_ir::TyVid;
+ fn from_vid(vid: rustc_type_ir::TyVid) -> InferenceVar;
+}
+
+impl InferenceVarExt for InferenceVar {
+ fn to_vid(self) -> rustc_type_ir::TyVid {
+ rustc_type_ir::TyVid::from_u32(self.index())
+ }
+ fn from_vid(vid: rustc_type_ir::TyVid) -> InferenceVar {
+ InferenceVar::from(vid.as_u32())
+ }
+}
diff --git a/crates/hir-ty/src/next_solver/solver.rs b/crates/hir-ty/src/next_solver/solver.rs
index 1d0ee0e488..b9b2950a94 100644
--- a/crates/hir-ty/src/next_solver/solver.rs
+++ b/crates/hir-ty/src/next_solver/solver.rs
@@ -14,7 +14,7 @@ use crate::{
db::HirDatabase,
next_solver::{
ClauseKind, CoercePredicate, PredicateKind, SubtypePredicate,
- mapping::{ChalkToNextSolver, convert_args_for_result},
+ mapping::ChalkToNextSolver,
util::sizedness_fast_path,
},
};
@@ -200,7 +200,7 @@ impl<'db> SolverDelegate for SolverContext<'db> {
SolverDefId::StaticId(c) => GeneralConstId::StaticId(c),
_ => unreachable!(),
};
- let subst = convert_args_for_result(self.interner, uv.args.as_slice());
+ let subst = ChalkToNextSolver::from_nextsolver(uv.args, self.interner);
let ec = self.cx().db.const_eval(c, subst, None).ok()?;
Some(ec.to_nextsolver(self.interner))
}
diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs
index 51cf5be137..0c58e031c3 100644
--- a/crates/hir-ty/src/traits.rs
+++ b/crates/hir-ty/src/traits.rs
@@ -1,6 +1,7 @@
//! Trait solving using Chalk.
use core::fmt;
+use std::hash::Hash;
use chalk_ir::{DebruijnIndex, GoalData, fold::TypeFoldable};
use chalk_solve::rust_ir;
@@ -20,17 +21,9 @@ use stdx::never;
use triomphe::Arc;
use crate::{
- AliasEq, AliasTy, Canonical, DomainGoal, Goal, InEnvironment, Interner, ProjectionTy,
- ProjectionTyExt, TraitRefExt, Ty, TyKind, TypeFlags, WhereClause,
- db::HirDatabase,
- infer::unify::InferenceTable,
- next_solver::{
- DbInterner, GenericArg, SolverContext, Span,
- infer::{DbInternerInferExt, InferCtxt},
- mapping::{ChalkToNextSolver, convert_canonical_args_for_result},
- util::mini_canonicalize,
- },
- utils::UnevaluatedConstEvaluatorFolder,
+ db::HirDatabase, infer::unify::InferenceTable, next_solver::{
+ infer::{DbInternerInferExt, InferCtxt}, mapping::{convert_canonical_args_for_result, ChalkToNextSolver}, util::mini_canonicalize, DbInterner, GenericArg, Predicate, SolverContext, Span
+ }, utils::UnevaluatedConstEvaluatorFolder, AliasEq, AliasTy, Canonical, DomainGoal, Goal, InEnvironment, Interner, ProjectionTy, ProjectionTyExt, TraitRefExt, Ty, TyKind, TypeFlags, WhereClause
};
/// A set of clauses that we assume to be true. E.g. if we are inside this function:
@@ -231,7 +224,6 @@ impl NextTraitSolveResult {
}
}
-/// Solve a trait goal using Chalk.
pub fn next_trait_solve(
db: &dyn HirDatabase,
krate: Crate,
@@ -290,6 +282,57 @@ pub fn next_trait_solve(
}
}
+pub fn next_trait_solve_canonical<'db>(
+ db: &'db dyn HirDatabase,
+ krate: Crate,
+ block: Option<BlockId>,
+ goal: crate::next_solver::Canonical<'db, crate::next_solver::Goal<'db, Predicate<'db>>>,
+) -> NextTraitSolveResult {
+ // FIXME: should use analysis_in_body, but that needs GenericDefId::Block
+ let context = SolverContext(
+ DbInterner::new_with(db, Some(krate), block)
+ .infer_ctxt()
+ .build(TypingMode::non_body_analysis()),
+ );
+
+ tracing::info!(?goal);
+
+ let (goal, var_values) =
+ context.instantiate_canonical(&goal);
+ tracing::info!(?var_values);
+
+ let res = context.evaluate_root_goal(
+ goal.clone(),
+ Span::dummy(),
+ None
+ );
+
+ let vars =
+ var_values.var_values.iter().map(|g| context.0.resolve_vars_if_possible(g)).collect();
+ let canonical_var_values = mini_canonicalize(context, vars);
+
+ let res = res.map(|r| (r.has_changed, r.certainty, canonical_var_values));
+
+ tracing::debug!("solve_nextsolver({:?}) => {:?}", goal, res);
+
+ match res {
+ Err(_) => NextTraitSolveResult::NoSolution,
+ Ok((_, Certainty::Yes, args)) => NextTraitSolveResult::Certain(
+ convert_canonical_args_for_result(DbInterner::new_with(db, Some(krate), block), args)
+ ),
+ Ok((_, Certainty::Maybe(_), args)) => {
+ let subst = convert_canonical_args_for_result(
+ DbInterner::new_with(db, Some(krate), block),
+ args,
+ );
+ NextTraitSolveResult::Uncertain(chalk_ir::Canonical {
+ binders: subst.binders,
+ value: subst.value.subst,
+ })
+ }
+ }
+}
+
/// Solve a trait goal using Chalk.
pub fn next_trait_solve_in_ctxt<'db, 'a>(
infer_ctxt: &'a InferCtxt<'db>,
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index 928753ef0e..79a154a5d8 100644
--- a/crates/hir/src/attrs.rs
+++ b/crates/hir/src/attrs.rs
@@ -14,7 +14,7 @@ use hir_expand::{
mod_path::{ModPath, PathKind},
name::Name,
};
-use hir_ty::{db::HirDatabase, method_resolution};
+use hir_ty::{db::HirDatabase, method_resolution, next_solver::{mapping::ChalkToNextSolver, DbInterner}};
use crate::{
Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, ExternCrateDecl,
@@ -271,7 +271,7 @@ fn resolve_impl_trait_item<'db>(
//
// FIXME: resolve type aliases (which are not yielded by iterate_path_candidates)
_ = method_resolution::iterate_path_candidates(
- &canonical,
+ &canonical.to_nextsolver(DbInterner::new_with(db, Some(environment.krate), environment.block)),
db,
environment,
&traits_in_scope,
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 6eb8a8bf60..52ab808d22 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -5611,7 +5611,11 @@ impl<'db> Type<'db> {
.map_or_else(|| TraitEnvironment::empty(krate.id), |d| db.trait_environment(d));
_ = method_resolution::iterate_method_candidates_dyn(
- &canonical,
+ &canonical.to_nextsolver(DbInterner::new_with(
+ db,
+ Some(environment.krate),
+ environment.block,
+ )),
db,
environment,
traits_in_scope,
@@ -5698,7 +5702,11 @@ impl<'db> Type<'db> {
.map_or_else(|| TraitEnvironment::empty(krate.id), |d| db.trait_environment(d));
_ = method_resolution::iterate_path_candidates(
- &canonical,
+ &canonical.to_nextsolver(DbInterner::new_with(
+ db,
+ Some(environment.krate),
+ environment.block,
+ )),
db,
environment,
traits_in_scope,