aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty/autoderef.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ty/autoderef.rs')
-rw-r--r--crates/ra_hir/src/ty/autoderef.rs68
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
6use std::iter::successors; 6use std::iter::successors;
7 7
8use crate::HirDatabase; 8use log::info;
9use super::Ty;
10 9
11impl Ty { 10use crate::{HirDatabase, Name, Resolver};
12 /// Iterates over the possible derefs of `ty`. 11use 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)) 13pub(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
21pub(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
33fn 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}