diff options
Diffstat (limited to 'crates/ra_hir/src/ty/autoderef.rs')
-rw-r--r-- | crates/ra_hir/src/ty/autoderef.rs | 68 |
1 files changed, 59 insertions, 9 deletions
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs index a442a856c..bee756d80 100644 --- a/crates/ra_hir/src/ty/autoderef.rs +++ b/crates/ra_hir/src/ty/autoderef.rs | |||
@@ -5,17 +5,67 @@ | |||
5 | 5 | ||
6 | use std::iter::successors; | 6 | use std::iter::successors; |
7 | 7 | ||
8 | use crate::HirDatabase; | 8 | use log::info; |
9 | use super::Ty; | ||
10 | 9 | ||
11 | impl Ty { | 10 | use crate::{HirDatabase, Name, Resolver}; |
12 | /// Iterates over the possible derefs of `ty`. | 11 | use super::{traits::Solution, Ty, Canonical}; |
13 | pub fn autoderef<'a>(self, db: &'a impl HirDatabase) -> impl Iterator<Item = Ty> + 'a { | 12 | |
14 | successors(Some(self), move |ty| ty.autoderef_step(db)) | 13 | pub(crate) fn autoderef<'a>( |
14 | db: &'a impl HirDatabase, | ||
15 | resolver: &'a Resolver, | ||
16 | ty: Canonical<Ty>, | ||
17 | ) -> impl Iterator<Item = Canonical<Ty>> + 'a { | ||
18 | successors(Some(ty), move |ty| deref(db, resolver, ty)) | ||
19 | } | ||
20 | |||
21 | pub(crate) fn deref( | ||
22 | db: &impl HirDatabase, | ||
23 | resolver: &Resolver, | ||
24 | ty: &Canonical<Ty>, | ||
25 | ) -> Option<Canonical<Ty>> { | ||
26 | if let Some(derefed) = ty.value.builtin_deref() { | ||
27 | Some(Canonical { value: derefed, num_vars: ty.num_vars }) | ||
28 | } else { | ||
29 | deref_by_trait(db, resolver, ty) | ||
15 | } | 30 | } |
31 | } | ||
32 | |||
33 | fn deref_by_trait( | ||
34 | db: &impl HirDatabase, | ||
35 | resolver: &Resolver, | ||
36 | ty: &Canonical<Ty>, | ||
37 | ) -> Option<Canonical<Ty>> { | ||
38 | let krate = resolver.krate()?; | ||
39 | let deref_trait = match db.lang_item(krate, "deref".into())? { | ||
40 | crate::lang_item::LangItemTarget::Trait(t) => t, | ||
41 | _ => return None, | ||
42 | }; | ||
43 | let target = deref_trait.associated_type_by_name(db, Name::target())?; | ||
44 | |||
45 | // FIXME we should check that Deref has no type parameters, because we assume it below | ||
46 | |||
47 | // FIXME make the Canonical handling nicer | ||
48 | // TODO shift inference variables in ty | ||
49 | |||
50 | let projection = super::traits::ProjectionPredicate { | ||
51 | ty: Ty::Bound(0), | ||
52 | projection_ty: super::ProjectionTy { | ||
53 | associated_ty: target, | ||
54 | parameters: vec![ty.value.clone()].into(), | ||
55 | }, | ||
56 | }; | ||
57 | |||
58 | let canonical = super::Canonical { num_vars: 1 + ty.num_vars, value: projection }; | ||
59 | |||
60 | let solution = db.normalize(krate, canonical)?; | ||
16 | 61 | ||
17 | fn autoderef_step(&self, _db: &impl HirDatabase) -> Option<Ty> { | 62 | match &solution { |
18 | // FIXME Deref::deref | 63 | Solution::Unique(vars) => { |
19 | self.builtin_deref() | 64 | Some(Canonical { value: vars.0.value[0].clone(), num_vars: vars.0.num_vars }) |
65 | } | ||
66 | Solution::Ambig(_) => { | ||
67 | info!("Ambiguous solution for deref: {:?}", solution); | ||
68 | None | ||
69 | } | ||
20 | } | 70 | } |
21 | } | 71 | } |