Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/traits.rs')
-rw-r--r--crates/hir-ty/src/traits.rs281
1 files changed, 23 insertions, 258 deletions
diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs
index cd125f3af8..7f6d4ff17f 100644
--- a/crates/hir-ty/src/traits.rs
+++ b/crates/hir-ty/src/traits.rs
@@ -3,35 +3,26 @@
use core::fmt;
use std::hash::Hash;
-use chalk_ir::{DebruijnIndex, GoalData, fold::TypeFoldable};
-
use base_db::Crate;
use hir_def::{BlockId, TraitId, lang_item::LangItem};
use hir_expand::name::Name;
use intern::sym;
use rustc_next_trait_solver::solve::{HasChanged, SolverDelegateEvalExt};
use rustc_type_ir::{
- InferCtxtLike, TypingMode,
- inherent::{IntoKind, SliceLike, Span as _, Ty as _},
+ TypingMode,
+ inherent::{IntoKind, Span as _},
solve::Certainty,
};
-use span::Edition;
-use stdx::never;
use triomphe::Arc;
use crate::{
- AliasEq, AliasTy, Canonical, DomainGoal, Goal, InEnvironment, Interner, ProjectionTy,
- ProjectionTyExt, TraitRefExt, Ty, TyKind, TypeFlags, WhereClause,
db::HirDatabase,
- from_assoc_type_id,
next_solver::{
- DbInterner, GenericArg, ParamEnv, Predicate, SolverContext, Span,
+ Canonical, DbInterner, GenericArgs, Goal, ParamEnv, Predicate, SolverContext, Span, Ty,
+ TyKind,
infer::{DbInternerInferExt, InferCtxt, traits::ObligationCause},
- mapping::{ChalkToNextSolver, NextSolverToChalk, convert_canonical_args_for_result},
obligation_ctxt::ObligationCtxt,
- util::mini_canonicalize,
},
- utils::UnevaluatedConstEvaluatorFolder,
};
/// A set of clauses that we assume to be true. E.g. if we are inside this function:
@@ -44,7 +35,7 @@ pub struct TraitEnvironment<'db> {
pub krate: Crate,
pub block: Option<BlockId>,
// FIXME make this a BTreeMap
- traits_from_clauses: Box<[(crate::next_solver::Ty<'db>, TraitId)]>,
+ traits_from_clauses: Box<[(Ty<'db>, TraitId)]>,
pub env: ParamEnv<'db>,
}
@@ -61,7 +52,7 @@ impl<'db> TraitEnvironment<'db> {
pub fn new(
krate: Crate,
block: Option<BlockId>,
- traits_from_clauses: Box<[(crate::next_solver::Ty<'db>, TraitId)]>,
+ traits_from_clauses: Box<[(Ty<'db>, TraitId)]>,
env: ParamEnv<'db>,
) -> Arc<Self> {
Arc::new(TraitEnvironment { krate, block, traits_from_clauses, env })
@@ -72,10 +63,7 @@ impl<'db> TraitEnvironment<'db> {
Arc::make_mut(this).block = Some(block);
}
- pub fn traits_in_scope_from_clauses(
- &self,
- ty: crate::next_solver::Ty<'db>,
- ) -> impl Iterator<Item = TraitId> + '_ {
+ pub fn traits_in_scope_from_clauses(&self, ty: Ty<'db>) -> impl Iterator<Item = TraitId> + '_ {
self.traits_from_clauses
.iter()
.filter_map(move |(self_ty, trait_id)| (*self_ty == ty).then_some(*trait_id))
@@ -85,172 +73,19 @@ impl<'db> TraitEnvironment<'db> {
/// This should be used in `hir` only.
pub fn structurally_normalize_ty<'db>(
infcx: &InferCtxt<'db>,
- ty: crate::next_solver::Ty<'db>,
+ ty: Ty<'db>,
env: Arc<TraitEnvironment<'db>>,
-) -> crate::next_solver::Ty<'db> {
- let crate::next_solver::TyKind::Alias(..) = ty.kind() else { return ty };
+) -> Ty<'db> {
+ let TyKind::Alias(..) = ty.kind() else { return ty };
let mut ocx = ObligationCtxt::new(infcx);
let ty = ocx.structurally_normalize_ty(&ObligationCause::dummy(), env.env, ty).unwrap_or(ty);
ty.replace_infer_with_error(infcx.interner)
}
-pub(crate) fn normalize_projection_query<'db>(
- db: &'db dyn HirDatabase,
- projection: ProjectionTy,
- env: Arc<TraitEnvironment<'db>>,
-) -> Ty {
- if projection.substitution.iter(Interner).any(|arg| {
- arg.ty(Interner)
- .is_some_and(|ty| ty.data(Interner).flags.intersects(TypeFlags::HAS_TY_INFER))
- }) {
- never!(
- "Invoking `normalize_projection_query` with a projection type containing inference var"
- );
- return TyKind::Error.intern(Interner);
- }
-
- let interner = DbInterner::new_with(db, Some(env.krate), env.block);
- // FIXME(next-solver): I believe this should use `PostAnalysis` (this is only used for IDE things),
- // but this causes some bug because of our incorrect impl of `type_of_opaque_hir_typeck()` for TAIT
- // and async blocks.
- let infcx = interner.infer_ctxt().build(TypingMode::Analysis {
- defining_opaque_types_and_generators: crate::next_solver::SolverDefIds::new_from_iter(
- interner,
- [],
- ),
- });
- let alias_ty = crate::next_solver::Ty::new_alias(
- interner,
- rustc_type_ir::AliasTyKind::Projection,
- crate::next_solver::AliasTy::new(
- interner,
- from_assoc_type_id(projection.associated_ty_id).into(),
- <crate::Substitution as ChalkToNextSolver<crate::next_solver::GenericArgs<'_>>>::to_nextsolver(&projection.substitution, interner),
- ),
- );
- let mut ctxt = crate::next_solver::obligation_ctxt::ObligationCtxt::new(&infcx);
- let normalized = ctxt
- .structurally_normalize_ty(&ObligationCause::dummy(), env.env, alias_ty)
- .unwrap_or(alias_ty);
- normalized.replace_infer_with_error(interner).to_chalk(interner)
-}
-
-fn identity_subst(
- binders: chalk_ir::CanonicalVarKinds<Interner>,
-) -> chalk_ir::Canonical<chalk_ir::Substitution<Interner>> {
- let identity_subst = chalk_ir::Substitution::from_iter(
- Interner,
- binders.iter(Interner).enumerate().map(|(index, c)| {
- let index_db = chalk_ir::BoundVar::new(DebruijnIndex::INNERMOST, index);
- match &c.kind {
- chalk_ir::VariableKind::Ty(_) => {
- chalk_ir::GenericArgData::Ty(TyKind::BoundVar(index_db).intern(Interner))
- .intern(Interner)
- }
- chalk_ir::VariableKind::Lifetime => chalk_ir::GenericArgData::Lifetime(
- chalk_ir::LifetimeData::BoundVar(index_db).intern(Interner),
- )
- .intern(Interner),
- chalk_ir::VariableKind::Const(ty) => chalk_ir::GenericArgData::Const(
- chalk_ir::ConstData {
- ty: ty.clone(),
- value: chalk_ir::ConstValue::BoundVar(index_db),
- }
- .intern(Interner),
- )
- .intern(Interner),
- }
- }),
- );
- chalk_ir::Canonical { binders, value: identity_subst }
-}
-
-/// Solve a trait goal using next trait solver.
-pub(crate) fn trait_solve_query(
- db: &dyn HirDatabase,
- krate: Crate,
- block: Option<BlockId>,
- goal: Canonical<InEnvironment<Goal>>,
-) -> NextTraitSolveResult {
- let _p = tracing::info_span!("trait_solve_query", detail = ?match &goal.value.goal.data(Interner) {
- GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => db
- .trait_signature(it.hir_trait_id())
- .name
- .display(db, Edition::LATEST)
- .to_string(),
- GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_owned(),
- _ => "??".to_owned(),
- })
- .entered();
-
- if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
- alias: AliasTy::Projection(projection_ty),
- ..
- }))) = &goal.value.goal.data(Interner)
- && let TyKind::BoundVar(_) = projection_ty.self_type_parameter(db).kind(Interner)
- {
- // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
- return NextTraitSolveResult::Uncertain(identity_subst(goal.binders.clone()));
- }
-
- // Chalk see `UnevaluatedConst` as a unique concrete value, but we see it as an alias for another const. So
- // we should get rid of it when talking to chalk.
- let goal = goal
- .try_fold_with(&mut UnevaluatedConstEvaluatorFolder { db }, DebruijnIndex::INNERMOST)
- .unwrap();
-
- // We currently don't deal with universes (I think / hope they're not yet
- // relevant for our use cases?)
- next_trait_solve(db, krate, block, goal)
-}
-
-fn solve_nextsolver<'db>(
- db: &'db dyn HirDatabase,
- krate: Crate,
- block: Option<BlockId>,
- goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>,
-) -> Result<
- (HasChanged, Certainty, rustc_type_ir::Canonical<DbInterner<'db>, Vec<GenericArg<'db>>>),
- rustc_type_ir::solve::NoSolution,
-> {
- // 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()),
- );
-
- match goal.canonical.value.goal.data(Interner) {
- // FIXME: args here should be...what? not empty
- GoalData::All(goals) if goals.is_empty(Interner) => {
- return Ok((HasChanged::No, Certainty::Yes, mini_canonicalize(context, vec![])));
- }
- _ => {}
- }
-
- let goal = goal.canonical.to_nextsolver(context.cx());
- tracing::info!(?goal);
-
- let (goal, var_values) = context.instantiate_canonical(&goal);
- tracing::info!(?var_values);
-
- let res = context.evaluate_root_goal(goal, 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);
-
- res
-}
-
#[derive(Clone, Debug, PartialEq)]
pub enum NextTraitSolveResult {
- Certain(chalk_ir::Canonical<chalk_ir::ConstrainedSubst<Interner>>),
- Uncertain(chalk_ir::Canonical<chalk_ir::Substitution<Interner>>),
+ Certain,
+ Uncertain,
NoSolution,
}
@@ -260,75 +95,17 @@ impl NextTraitSolveResult {
}
pub fn certain(&self) -> bool {
- matches!(self, NextTraitSolveResult::Certain(..))
+ matches!(self, NextTraitSolveResult::Certain)
}
pub fn uncertain(&self) -> bool {
- matches!(self, NextTraitSolveResult::Uncertain(..))
- }
-}
-
-pub fn next_trait_solve(
- db: &dyn HirDatabase,
- krate: Crate,
- block: Option<BlockId>,
- goal: Canonical<InEnvironment<Goal>>,
-) -> NextTraitSolveResult {
- let detail = match &goal.value.goal.data(Interner) {
- GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => {
- db.trait_signature(it.hir_trait_id()).name.display(db, Edition::LATEST).to_string()
- }
- GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_owned(),
- _ => "??".to_owned(),
- };
- let _p = tracing::info_span!("next_trait_solve", ?detail).entered();
- tracing::info!("next_trait_solve({:?})", goal.value.goal);
-
- if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
- alias: AliasTy::Projection(projection_ty),
- ..
- }))) = &goal.value.goal.data(Interner)
- && let TyKind::BoundVar(_) = projection_ty.self_type_parameter(db).kind(Interner)
- {
- // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
- // FIXME
- return NextTraitSolveResult::Uncertain(identity_subst(goal.binders.clone()));
- }
-
- // Chalk see `UnevaluatedConst` as a unique concrete value, but we see it as an alias for another const. So
- // we should get rid of it when talking to chalk.
- let goal = goal
- .try_fold_with(&mut UnevaluatedConstEvaluatorFolder { db }, DebruijnIndex::INNERMOST)
- .unwrap();
-
- // We currently don't deal with universes (I think / hope they're not yet
- // relevant for our use cases?)
- let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 };
- tracing::info!(?u_canonical);
-
- let next_solver_res = solve_nextsolver(db, krate, block, &u_canonical);
-
- match next_solver_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,
- })
- }
+ matches!(self, NextTraitSolveResult::Uncertain)
}
}
pub fn next_trait_solve_canonical_in_ctxt<'db>(
infer_ctxt: &InferCtxt<'db>,
- goal: crate::next_solver::Canonical<'db, crate::next_solver::Goal<'db, Predicate<'db>>>,
+ goal: Canonical<'db, Goal<'db, Predicate<'db>>>,
) -> NextTraitSolveResult {
let context = SolverContext(infer_ctxt.clone());
@@ -339,33 +116,21 @@ pub fn next_trait_solve_canonical_in_ctxt<'db>(
let res = context.evaluate_root_goal(goal, 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));
+ let res = res.map(|r| (r.has_changed, r.certainty));
tracing::debug!("solve_nextsolver({:?}) => {:?}", goal, res);
match res {
Err(_) => NextTraitSolveResult::NoSolution,
- Ok((_, Certainty::Yes, args)) => NextTraitSolveResult::Certain(
- convert_canonical_args_for_result(infer_ctxt.interner, args),
- ),
- Ok((_, Certainty::Maybe { .. }, args)) => {
- let subst = convert_canonical_args_for_result(infer_ctxt.interner, args);
- NextTraitSolveResult::Uncertain(chalk_ir::Canonical {
- binders: subst.binders,
- value: subst.value.subst,
- })
- }
+ Ok((_, Certainty::Yes)) => NextTraitSolveResult::Certain,
+ Ok((_, Certainty::Maybe { .. })) => NextTraitSolveResult::Uncertain,
}
}
/// Solve a trait goal using next trait solver.
pub fn next_trait_solve_in_ctxt<'db, 'a>(
infer_ctxt: &'a InferCtxt<'db>,
- goal: crate::next_solver::Goal<'db, crate::next_solver::Predicate<'db>>,
+ goal: Goal<'db, Predicate<'db>>,
) -> Result<(HasChanged, Certainty), rustc_type_ir::solve::NoSolution> {
tracing::info!(?goal);
@@ -459,7 +224,7 @@ impl FnTrait {
/// This should not be used in `hir-ty`, only in `hir`.
pub fn implements_trait_unique<'db>(
- ty: crate::next_solver::Ty<'db>,
+ ty: Ty<'db>,
db: &'db dyn HirDatabase,
env: Arc<TraitEnvironment<'db>>,
trait_: TraitId,
@@ -474,7 +239,7 @@ pub fn implements_trait_unique_with_args<'db>(
db: &'db dyn HirDatabase,
env: Arc<TraitEnvironment<'db>>,
trait_: TraitId,
- args: crate::next_solver::GenericArgs<'db>,
+ args: GenericArgs<'db>,
) -> bool {
implements_trait_unique_impl(db, env, trait_, &mut |_| args)
}
@@ -483,7 +248,7 @@ fn implements_trait_unique_impl<'db>(
db: &'db dyn HirDatabase,
env: Arc<TraitEnvironment<'db>>,
trait_: TraitId,
- create_args: &mut dyn FnMut(&InferCtxt<'db>) -> crate::next_solver::GenericArgs<'db>,
+ create_args: &mut dyn FnMut(&InferCtxt<'db>) -> GenericArgs<'db>,
) -> bool {
let interner = DbInterner::new_with(db, Some(env.krate), env.block);
// FIXME(next-solver): I believe this should be `PostAnalysis`.
@@ -491,7 +256,7 @@ fn implements_trait_unique_impl<'db>(
let args = create_args(&infcx);
let trait_ref = rustc_type_ir::TraitRef::new_from_args(interner, trait_.into(), args);
- let goal = crate::next_solver::Goal::new(interner, env.env, trait_ref);
+ let goal = Goal::new(interner, env.env, trait_ref);
let result = crate::traits::next_trait_solve_in_ctxt(&infcx, goal);
matches!(result, Ok((_, Certainty::Yes)))