aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/traits.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src/traits.rs')
-rw-r--r--crates/ra_hir_ty/src/traits.rs113
1 files changed, 18 insertions, 95 deletions
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs
index 6bc6d474c..3f6d2cf35 100644
--- a/crates/ra_hir_ty/src/traits.rs
+++ b/crates/ra_hir_ty/src/traits.rs
@@ -1,20 +1,19 @@
1//! Trait solving using Chalk. 1//! Trait solving using Chalk.
2use std::{panic, sync::Arc}; 2use std::sync::Arc;
3 3
4use chalk_ir::cast::Cast; 4use chalk_ir::cast::Cast;
5use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId}; 5use chalk_solve::Solver;
6use ra_db::{impl_intern_key, salsa, CrateId}; 6use hir_def::{lang_item::LangItemTarget, TraitId};
7use ra_db::CrateId;
7use ra_prof::profile; 8use ra_prof::profile;
8use rustc_hash::FxHashSet;
9 9
10use crate::{db::HirDatabase, method_resolution::TyFingerprint, DebruijnIndex}; 10use crate::{db::HirDatabase, DebruijnIndex, Substs};
11 11
12use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; 12use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
13 13
14use self::chalk::{from_chalk, Interner, ToChalk}; 14use self::chalk::{from_chalk, Interner, ToChalk};
15 15
16pub(crate) mod chalk; 16pub(crate) mod chalk;
17mod builtin;
18 17
19// This controls the maximum size of types Chalk considers. If we set this too 18// This controls the maximum size of types Chalk considers. If we set this too
20// high, we can run into slow edge cases; if we set it too low, Chalk won't 19// high, we can run into slow edge cases; if we set it too low, Chalk won't
@@ -31,37 +30,10 @@ struct ChalkContext<'a> {
31 krate: CrateId, 30 krate: CrateId,
32} 31}
33 32
34fn create_chalk_solver() -> chalk_solve::Solver<Interner> { 33fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
35 let solver_choice = chalk_solve::SolverChoice::recursive(); 34 let overflow_depth = 100;
36 solver_choice.into_solver() 35 let caching_enabled = true;
37} 36 chalk_recursive::RecursiveSolver::new(overflow_depth, caching_enabled)
38
39/// Collects impls for the given trait in the whole dependency tree of `krate`.
40pub(crate) fn impls_for_trait_query(
41 db: &dyn HirDatabase,
42 krate: CrateId,
43 trait_: TraitId,
44 self_ty_fp: Option<TyFingerprint>,
45) -> Arc<[ImplId]> {
46 // FIXME: We could be a lot smarter here - because of the orphan rules and
47 // the fact that the trait and the self type need to be in the dependency
48 // tree of a crate somewhere for an impl to exist, we could skip looking in
49 // a lot of crates completely
50 let mut impls = FxHashSet::default();
51 // We call the query recursively here. On the one hand, this means we can
52 // reuse results from queries for different crates; on the other hand, this
53 // will only ever get called for a few crates near the root of the tree (the
54 // ones the user is editing), so this may actually be a waste of memory. I'm
55 // doing it like this mainly for simplicity for now.
56 for dep in &db.crate_graph()[krate].dependencies {
57 impls.extend(db.impls_for_trait(dep.crate_id, trait_, self_ty_fp).iter());
58 }
59 let crate_impl_defs = db.impls_in_crate(krate);
60 match self_ty_fp {
61 Some(fp) => impls.extend(crate_impl_defs.lookup_impl_defs_for_trait_and_ty(trait_, fp)),
62 None => impls.extend(crate_impl_defs.lookup_impl_defs_for_trait(trait_)),
63 }
64 impls.into_iter().collect()
65} 37}
66 38
67/// A set of clauses that we assume to be true. E.g. if we are inside this function: 39/// A set of clauses that we assume to be true. E.g. if we are inside this function:
@@ -217,15 +189,7 @@ fn solution_from_chalk(
217 solution: chalk_solve::Solution<Interner>, 189 solution: chalk_solve::Solution<Interner>,
218) -> Solution { 190) -> Solution {
219 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<Interner>>| { 191 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<Interner>>| {
220 let value = subst 192 let result = from_chalk(db, subst);
221 .value
222 .iter(&Interner)
223 .map(|p| match p.ty(&Interner) {
224 Some(ty) => from_chalk(db, ty.clone()),
225 None => unimplemented!(),
226 })
227 .collect();
228 let result = Canonical { value, num_vars: subst.binders.len(&Interner) };
229 SolutionVariables(result) 193 SolutionVariables(result)
230 }; 194 };
231 match solution { 195 match solution {
@@ -249,7 +213,7 @@ fn solution_from_chalk(
249} 213}
250 214
251#[derive(Clone, Debug, PartialEq, Eq)] 215#[derive(Clone, Debug, PartialEq, Eq)]
252pub struct SolutionVariables(pub Canonical<Vec<Ty>>); 216pub struct SolutionVariables(pub Canonical<Substs>);
253 217
254#[derive(Clone, Debug, PartialEq, Eq)] 218#[derive(Clone, Debug, PartialEq, Eq)]
255/// A (possible) solution for a proposed goal. 219/// A (possible) solution for a proposed goal.
@@ -298,53 +262,12 @@ impl FnTrait {
298 FnTrait::Fn => "fn", 262 FnTrait::Fn => "fn",
299 } 263 }
300 } 264 }
301}
302 265
303#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 266 pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
304pub struct ClosureFnTraitImplData { 267 let target = db.lang_item(krate, self.lang_item_name().into())?;
305 def: DefWithBodyId, 268 match target {
306 expr: ExprId, 269 LangItemTarget::TraitId(t) => Some(t),
307 fn_trait: FnTrait, 270 _ => None,
308} 271 }
309 272 }
310#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
311pub struct UnsizeToSuperTraitObjectData {
312 trait_: TraitId,
313 super_trait: TraitId,
314}
315
316/// An impl. Usually this comes from an impl block, but some built-in types get
317/// synthetic impls.
318#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
319pub enum Impl {
320 /// A normal impl from an impl block.
321 ImplDef(ImplId),
322 /// Closure types implement the Fn traits synthetically.
323 ClosureFnTraitImpl(ClosureFnTraitImplData),
324 /// [T; n]: Unsize<[T]>
325 UnsizeArray,
326 /// T: Unsize<dyn Trait> where T: Trait
327 UnsizeToTraitObject(TraitId),
328 /// dyn Trait: Unsize<dyn SuperTrait> if Trait: SuperTrait
329 UnsizeToSuperTraitObject(UnsizeToSuperTraitObjectData),
330}
331/// This exists just for Chalk, because our ImplIds are only unique per module.
332#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
333pub struct GlobalImplId(salsa::InternId);
334impl_intern_key!(GlobalImplId);
335
336/// An associated type value. Usually this comes from a `type` declaration
337/// inside an impl block, but for built-in impls we have to synthesize it.
338/// (We only need this because Chalk wants a unique ID for each of these.)
339#[derive(Debug, Clone, PartialEq, Eq, Hash)]
340pub enum AssocTyValue {
341 /// A normal assoc type value from an impl block.
342 TypeAlias(TypeAliasId),
343 /// The output type of the Fn trait implementation.
344 ClosureFnTraitImplOutput(ClosureFnTraitImplData),
345} 273}
346/// This exists just for Chalk, because it needs a unique ID for each associated
347/// type value in an impl (even synthetic ones).
348#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
349pub struct AssocTyValueId(salsa::InternId);
350impl_intern_key!(AssocTyValueId);