diff options
Diffstat (limited to 'crates/ra_hir_ty/src/traits.rs')
-rw-r--r-- | crates/ra_hir_ty/src/traits.rs | 113 |
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. |
2 | use std::{panic, sync::Arc}; | 2 | use std::sync::Arc; |
3 | 3 | ||
4 | use chalk_ir::cast::Cast; | 4 | use chalk_ir::cast::Cast; |
5 | use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId}; | 5 | use chalk_solve::Solver; |
6 | use ra_db::{impl_intern_key, salsa, CrateId}; | 6 | use hir_def::{lang_item::LangItemTarget, TraitId}; |
7 | use ra_db::CrateId; | ||
7 | use ra_prof::profile; | 8 | use ra_prof::profile; |
8 | use rustc_hash::FxHashSet; | ||
9 | 9 | ||
10 | use crate::{db::HirDatabase, method_resolution::TyFingerprint, DebruijnIndex}; | 10 | use crate::{db::HirDatabase, DebruijnIndex, Substs}; |
11 | 11 | ||
12 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; | 12 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; |
13 | 13 | ||
14 | use self::chalk::{from_chalk, Interner, ToChalk}; | 14 | use self::chalk::{from_chalk, Interner, ToChalk}; |
15 | 15 | ||
16 | pub(crate) mod chalk; | 16 | pub(crate) mod chalk; |
17 | mod 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 | ||
34 | fn create_chalk_solver() -> chalk_solve::Solver<Interner> { | 33 | fn 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`. | ||
40 | pub(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)] |
252 | pub struct SolutionVariables(pub Canonical<Vec<Ty>>); | 216 | pub 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> { |
304 | pub 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)] | ||
311 | pub 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)] | ||
319 | pub 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)] | ||
333 | pub struct GlobalImplId(salsa::InternId); | ||
334 | impl_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)] | ||
340 | pub 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)] | ||
349 | pub struct AssocTyValueId(salsa::InternId); | ||
350 | impl_intern_key!(AssocTyValueId); | ||