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.rs55
1 files changed, 43 insertions, 12 deletions
diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs
index 3ab85c68f5..f40b7db3a5 100644
--- a/crates/hir-ty/src/traits.rs
+++ b/crates/hir-ty/src/traits.rs
@@ -1,22 +1,24 @@
//! Trait solving using Chalk.
-use std::{env::var, sync::Arc};
+use std::env::var;
-use chalk_ir::GoalData;
+use chalk_ir::{fold::TypeFoldable, DebruijnIndex, GoalData};
use chalk_recursive::Cache;
-use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};
+use chalk_solve::{logging_db::LoggingRustIrDatabase, rust_ir, Solver};
use base_db::CrateId;
use hir_def::{
lang_item::{LangItem, LangItemTarget},
- TraitId,
+ BlockId, TraitId,
};
+use hir_expand::name::{name, Name};
use stdx::panic_context;
+use triomphe::Arc;
use crate::{
- db::HirDatabase, infer::unify::InferenceTable, AliasEq, AliasTy, Canonical, DomainGoal, Goal,
- Guidance, InEnvironment, Interner, ProjectionTy, ProjectionTyExt, Solution, TraitRefExt, Ty,
- TyKind, WhereClause,
+ db::HirDatabase, infer::unify::InferenceTable, utils::UnevaluatedConstEvaluatorFolder, AliasEq,
+ AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment, Interner, ProjectionTy,
+ ProjectionTyExt, Solution, TraitRefExt, Ty, TyKind, WhereClause,
};
/// This controls how much 'time' we give the Chalk solver before giving up.
@@ -26,6 +28,7 @@ const CHALK_SOLVER_FUEL: i32 = 1000;
pub(crate) struct ChalkContext<'a> {
pub(crate) db: &'a dyn HirDatabase,
pub(crate) krate: CrateId,
+ pub(crate) block: Option<BlockId>,
}
fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
@@ -43,6 +46,7 @@ fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TraitEnvironment {
pub krate: CrateId,
+ pub block: Option<BlockId>,
// FIXME make this a BTreeMap
pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>,
pub env: chalk_ir::Environment<Interner>,
@@ -52,6 +56,7 @@ impl TraitEnvironment {
pub fn empty(krate: CrateId) -> Self {
TraitEnvironment {
krate,
+ block: None,
traits_from_clauses: Vec::new(),
env: chalk_ir::Environment::new(Interner),
}
@@ -78,11 +83,12 @@ pub(crate) fn normalize_projection_query(
pub(crate) fn trait_solve_query(
db: &dyn HirDatabase,
krate: CrateId,
+ block: Option<BlockId>,
goal: Canonical<InEnvironment<Goal>>,
) -> Option<Solution> {
let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal.data(Interner) {
GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => {
- db.trait_data(it.hir_trait_id()).name.to_string()
+ db.trait_data(it.hir_trait_id()).name.display(db.upcast()).to_string()
}
GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_string(),
_ => "??".to_string(),
@@ -100,18 +106,25 @@ pub(crate) fn trait_solve_query(
}
}
+ // 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 };
- solve(db, krate, &u_canonical)
+ solve(db, krate, block, &u_canonical)
}
fn solve(
db: &dyn HirDatabase,
krate: CrateId,
+ block: Option<BlockId>,
goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>,
) -> Option<chalk_solve::Solution<Interner>> {
- let context = ChalkContext { db, krate };
+ let context = ChalkContext { db, krate, block };
tracing::debug!("solve goal: {:?}", goal);
let mut solver = create_chalk_solver();
@@ -171,8 +184,10 @@ fn is_chalk_print() -> bool {
std::env::var("CHALK_PRINT").is_ok()
}
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum FnTrait {
+ // Warning: Order is important. If something implements `x` it should also implement
+ // `y` if `y <= x`.
FnOnce,
FnMut,
Fn,
@@ -187,7 +202,23 @@ impl FnTrait {
}
}
- pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
+ pub const fn to_chalk_ir(self) -> rust_ir::ClosureKind {
+ match self {
+ FnTrait::FnOnce => rust_ir::ClosureKind::FnOnce,
+ FnTrait::FnMut => rust_ir::ClosureKind::FnMut,
+ FnTrait::Fn => rust_ir::ClosureKind::Fn,
+ }
+ }
+
+ pub fn method_name(self) -> Name {
+ match self {
+ FnTrait::FnOnce => name!(call_once),
+ FnTrait::FnMut => name!(call_mut),
+ FnTrait::Fn => name!(call),
+ }
+ }
+
+ pub fn get_id(self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
let target = db.lang_item(krate, self.lang_item())?;
match target {
LangItemTarget::Trait(t) => Some(t),