diff options
author | Florian Diebold <[email protected]> | 2019-05-12 17:33:47 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-06-15 17:21:23 +0100 |
commit | 9c5e7dd849eff7bd6f20aa353feef083d089ff58 (patch) | |
tree | 5639ff8814d3f4ba0f5ac41de215ed3720f3d1b9 /crates/ra_hir/src/ty | |
parent | 49489dc20cc9f340d43acb467677b9bc59495ed2 (diff) |
Implement autoderef using the Deref trait
- add support for other lang item targets, since we need the Deref lang item
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r-- | crates/ra_hir/src/ty/autoderef.rs | 68 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 40 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits.rs | 4 |
4 files changed, 84 insertions, 33 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 | } |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index e150d7fd8..fdb444de2 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -46,7 +46,7 @@ use crate::{ | |||
46 | use super::{ | 46 | use super::{ |
47 | Ty, TypableDef, Substs, primitive, op, ApplicationTy, TypeCtor, CallableDef, TraitRef, | 47 | Ty, TypableDef, Substs, primitive, op, ApplicationTy, TypeCtor, CallableDef, TraitRef, |
48 | traits::{Solution, Obligation, Guidance}, | 48 | traits::{Solution, Obligation, Guidance}, |
49 | method_resolution, | 49 | method_resolution, autoderef, |
50 | }; | 50 | }; |
51 | 51 | ||
52 | mod unify; | 52 | mod unify; |
@@ -1074,25 +1074,27 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1074 | } | 1074 | } |
1075 | Expr::Field { expr, name } => { | 1075 | Expr::Field { expr, name } => { |
1076 | let receiver_ty = self.infer_expr(*expr, &Expectation::none()); | 1076 | let receiver_ty = self.infer_expr(*expr, &Expectation::none()); |
1077 | let ty = receiver_ty | 1077 | let canonicalized = self.canonicalizer().canonicalize_ty(receiver_ty); |
1078 | .autoderef(self.db) | 1078 | let ty = autoderef::autoderef( |
1079 | .find_map(|derefed_ty| match derefed_ty { | 1079 | self.db, |
1080 | Ty::Apply(a_ty) => match a_ty.ctor { | 1080 | &self.resolver.clone(), |
1081 | TypeCtor::Tuple { .. } => { | 1081 | canonicalized.value.clone(), |
1082 | let i = name.to_string().parse::<usize>().ok(); | 1082 | ) |
1083 | i.and_then(|i| a_ty.parameters.0.get(i).cloned()) | 1083 | .find_map(|derefed_ty| match canonicalized.decanonicalize_ty(derefed_ty.value) { |
1084 | } | 1084 | Ty::Apply(a_ty) => match a_ty.ctor { |
1085 | TypeCtor::Adt(AdtDef::Struct(s)) => { | 1085 | TypeCtor::Tuple { .. } => { |
1086 | s.field(self.db, name).map(|field| { | 1086 | let i = name.to_string().parse::<usize>().ok(); |
1087 | self.write_field_resolution(tgt_expr, field); | 1087 | i.and_then(|i| a_ty.parameters.0.get(i).cloned()) |
1088 | field.ty(self.db).subst(&a_ty.parameters) | 1088 | } |
1089 | }) | 1089 | TypeCtor::Adt(AdtDef::Struct(s)) => s.field(self.db, name).map(|field| { |
1090 | } | 1090 | self.write_field_resolution(tgt_expr, field); |
1091 | _ => None, | 1091 | field.ty(self.db).subst(&a_ty.parameters) |
1092 | }, | 1092 | }), |
1093 | _ => None, | 1093 | _ => None, |
1094 | }) | 1094 | }, |
1095 | .unwrap_or(Ty::Unknown); | 1095 | _ => None, |
1096 | }) | ||
1097 | .unwrap_or(Ty::Unknown); | ||
1096 | self.insert_type_vars(ty) | 1098 | self.insert_type_vars(ty) |
1097 | } | 1099 | } |
1098 | Expr::Try { expr } => { | 1100 | Expr::Try { expr } => { |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 646e58aa9..ad26d591c 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -16,7 +16,7 @@ use crate::{ | |||
16 | generics::HasGenericParams, | 16 | generics::HasGenericParams, |
17 | ty::primitive::{UncertainIntTy, UncertainFloatTy} | 17 | ty::primitive::{UncertainIntTy, UncertainFloatTy} |
18 | }; | 18 | }; |
19 | use super::{TraitRef, Canonical}; | 19 | use super::{TraitRef, Canonical, autoderef}; |
20 | 20 | ||
21 | /// This is used as a key for indexing impls. | 21 | /// This is used as a key for indexing impls. |
22 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | 22 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
@@ -162,8 +162,7 @@ pub(crate) fn iterate_method_candidates<T>( | |||
162 | // rustc does an autoderef and then autoref again). | 162 | // rustc does an autoderef and then autoref again). |
163 | 163 | ||
164 | let krate = resolver.krate()?; | 164 | let krate = resolver.krate()?; |
165 | for derefed_ty in ty.value.clone().autoderef(db) { | 165 | for derefed_ty in autoderef::autoderef(db, resolver, ty.clone()) { |
166 | let derefed_ty = Canonical { value: derefed_ty, num_vars: ty.num_vars }; | ||
167 | if let Some(result) = iterate_inherent_methods(&derefed_ty, db, name, krate, &mut callback) | 166 | if let Some(result) = iterate_inherent_methods(&derefed_ty, db, name, krate, &mut callback) |
168 | { | 167 | { |
169 | return Some(result); | 168 | return Some(result); |
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs index f3e488403..6cf3dd70a 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs | |||
@@ -80,8 +80,8 @@ pub enum Obligation { | |||
80 | 80 | ||
81 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | 81 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] |
82 | pub struct ProjectionPredicate { | 82 | pub struct ProjectionPredicate { |
83 | projection_ty: ProjectionTy, | 83 | pub projection_ty: ProjectionTy, |
84 | ty: Ty, | 84 | pub ty: Ty, |
85 | } | 85 | } |
86 | 86 | ||
87 | /// Check using Chalk whether trait is implemented for given parameters including `Self` type. | 87 | /// Check using Chalk whether trait is implemented for given parameters including `Self` type. |