aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-05-12 17:33:47 +0100
committerFlorian Diebold <[email protected]>2019-06-15 17:21:23 +0100
commit9c5e7dd849eff7bd6f20aa353feef083d089ff58 (patch)
tree5639ff8814d3f4ba0f5ac41de215ed3720f3d1b9 /crates/ra_hir/src/ty
parent49489dc20cc9f340d43acb467677b9bc59495ed2 (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.rs68
-rw-r--r--crates/ra_hir/src/ty/infer.rs40
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs5
-rw-r--r--crates/ra_hir/src/ty/traits.rs4
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
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}
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::{
46use super::{ 46use 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
52mod unify; 52mod 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};
19use super::{TraitRef, Canonical}; 19use 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)]
82pub struct ProjectionPredicate { 82pub 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.