aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty
diff options
context:
space:
mode:
authorMarco Groppo <[email protected]>2019-03-26 19:26:16 +0000
committerMarco Groppo <[email protected]>2019-03-26 19:26:16 +0000
commit6030d6f500e42bde012a391666b68363d8479d21 (patch)
tree42c799a75b1803afe1838818de86cebe9674c38a /crates/ra_hir/src/ty
parent12b5d4f795f69f7fa07051cdec7a1347d3aa7924 (diff)
parent1011e37f3a260b0565f88c84d3c49fac1ec7b879 (diff)
Merge branch 'master' of github.com:rust-analyzer/rust-analyzer into flip-binexpr
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r--crates/ra_hir/src/ty/infer.rs3
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs95
-rw-r--r--crates/ra_hir/src/ty/tests.rs12
3 files changed, 84 insertions, 26 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 5fd602a9e..573115321 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -821,7 +821,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
821 } 821 }
822 Expr::MethodCall { receiver, args, method_name, generic_args } => { 822 Expr::MethodCall { receiver, args, method_name, generic_args } => {
823 let receiver_ty = self.infer_expr(*receiver, &Expectation::none()); 823 let receiver_ty = self.infer_expr(*receiver, &Expectation::none());
824 let resolved = receiver_ty.clone().lookup_method(self.db, method_name); 824 let resolved =
825 receiver_ty.clone().lookup_method(self.db, method_name, &self.resolver);
825 let (derefed_receiver_ty, method_ty, def_generics) = match resolved { 826 let (derefed_receiver_ty, method_ty, def_generics) = match resolved {
826 Some((ty, func)) => { 827 Some((ty, func)) => {
827 self.write_method_resolution(tgt_expr, func); 828 self.write_method_resolution(tgt_expr, func);
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index b1684acf9..3ac8dc46b 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -8,12 +8,12 @@ use rustc_hash::FxHashMap;
8 8
9use crate::{ 9use crate::{
10 HirDatabase, Module, Crate, Name, Function, Trait, 10 HirDatabase, Module, Crate, Name, Function, Trait,
11 ids::TraitId,
12 impl_block::{ImplId, ImplBlock, ImplItem}, 11 impl_block::{ImplId, ImplBlock, ImplItem},
13 ty::{Ty, TypeCtor}, 12 ty::{Ty, TypeCtor},
14 nameres::CrateModuleId, 13 nameres::CrateModuleId, resolve::Resolver, traits::TraitItem
15 14
16}; 15};
16use super::{ TraitRef, Substs};
17 17
18/// This is used as a key for indexing impls. 18/// This is used as a key for indexing impls.
19#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 19#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -38,7 +38,7 @@ pub struct CrateImplBlocks {
38 /// To make sense of the CrateModuleIds, we need the source root. 38 /// To make sense of the CrateModuleIds, we need the source root.
39 krate: Crate, 39 krate: Crate,
40 impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>, 40 impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>,
41 impls_by_trait: FxHashMap<TraitId, Vec<(CrateModuleId, ImplId)>>, 41 impls_by_trait: FxHashMap<Trait, Vec<(CrateModuleId, ImplId)>>,
42} 42}
43 43
44impl CrateImplBlocks { 44impl CrateImplBlocks {
@@ -56,8 +56,7 @@ impl CrateImplBlocks {
56 &'a self, 56 &'a self,
57 tr: &Trait, 57 tr: &Trait,
58 ) -> impl Iterator<Item = ImplBlock> + 'a { 58 ) -> impl Iterator<Item = ImplBlock> + 'a {
59 let id = tr.id; 59 self.impls_by_trait.get(&tr).into_iter().flat_map(|i| i.iter()).map(
60 self.impls_by_trait.get(&id).into_iter().flat_map(|i| i.iter()).map(
61 move |(module_id, impl_id)| { 60 move |(module_id, impl_id)| {
62 let module = Module { krate: self.krate, module_id: *module_id }; 61 let module = Module { krate: self.krate, module_id: *module_id };
63 ImplBlock::from_id(module, *impl_id) 62 ImplBlock::from_id(module, *impl_id)
@@ -73,18 +72,18 @@ impl CrateImplBlocks {
73 72
74 let target_ty = impl_block.target_ty(db); 73 let target_ty = impl_block.target_ty(db);
75 74
76 if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
77 self.impls
78 .entry(target_ty_fp)
79 .or_insert_with(Vec::new)
80 .push((module.module_id, impl_id));
81 }
82
83 if let Some(tr) = impl_block.target_trait(db) { 75 if let Some(tr) = impl_block.target_trait(db) {
84 self.impls_by_trait 76 self.impls_by_trait
85 .entry(tr.id) 77 .entry(tr)
86 .or_insert_with(Vec::new) 78 .or_insert_with(Vec::new)
87 .push((module.module_id, impl_id)); 79 .push((module.module_id, impl_id));
80 } else {
81 if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
82 self.impls
83 .entry(target_ty_fp)
84 .or_insert_with(Vec::new)
85 .push((module.module_id, impl_id));
86 }
88 } 87 }
89 } 88 }
90 89
@@ -109,6 +108,20 @@ impl CrateImplBlocks {
109 } 108 }
110} 109}
111 110
111/// Rudimentary check whether an impl exists for a given type and trait; this
112/// will actually be done by chalk.
113pub(crate) fn implements(db: &impl HirDatabase, trait_ref: TraitRef) -> bool {
114 // FIXME use all trait impls in the whole crate graph
115 let krate = trait_ref.trait_.module(db).krate(db);
116 let krate = match krate {
117 Some(krate) => krate,
118 None => return false,
119 };
120 let crate_impl_blocks = db.impls_in_crate(krate);
121 let mut impl_blocks = crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_ref.trait_);
122 impl_blocks.any(|impl_block| &impl_block.target_ty(db) == trait_ref.self_ty())
123}
124
112fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { 125fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> {
113 match ty { 126 match ty {
114 Ty::Apply(a_ty) => match a_ty.ctor { 127 Ty::Apply(a_ty) => match a_ty.ctor {
@@ -120,20 +133,64 @@ fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> {
120} 133}
121 134
122impl Ty { 135impl Ty {
123 // FIXME: cache this as a query?
124 // - if so, what signature? (TyFingerprint, Name)?
125 // - or maybe cache all names and def_ids of methods per fingerprint?
126 /// Look up the method with the given name, returning the actual autoderefed 136 /// Look up the method with the given name, returning the actual autoderefed
127 /// receiver type (but without autoref applied yet). 137 /// receiver type (but without autoref applied yet).
128 pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<(Ty, Function)> { 138 pub fn lookup_method(
129 self.iterate_methods(db, |ty, f| { 139 self,
140 db: &impl HirDatabase,
141 name: &Name,
142 resolver: &Resolver,
143 ) -> Option<(Ty, Function)> {
144 // FIXME: trait methods should be used before autoderefs
145 let inherent_method = self.clone().iterate_methods(db, |ty, f| {
130 let sig = f.signature(db); 146 let sig = f.signature(db);
131 if sig.name() == name && sig.has_self_param() { 147 if sig.name() == name && sig.has_self_param() {
132 Some((ty.clone(), f)) 148 Some((ty.clone(), f))
133 } else { 149 } else {
134 None 150 None
135 } 151 }
136 }) 152 });
153 inherent_method.or_else(|| self.lookup_trait_method(db, name, resolver))
154 }
155
156 fn lookup_trait_method(
157 self,
158 db: &impl HirDatabase,
159 name: &Name,
160 resolver: &Resolver,
161 ) -> Option<(Ty, Function)> {
162 let mut candidates = Vec::new();
163 for t in resolver.traits_in_scope() {
164 let data = t.trait_data(db);
165 for item in data.items() {
166 match item {
167 &TraitItem::Function(m) => {
168 let sig = m.signature(db);
169 if sig.name() == name && sig.has_self_param() {
170 candidates.push((t, m));
171 }
172 }
173 _ => {}
174 }
175 }
176 }
177 // FIXME:
178 // - we might not actually be able to determine fully that the type
179 // implements the trait here; it's enough if we (well, Chalk) determine
180 // that it's possible.
181 // - when the trait method is picked, we need to register an
182 // 'obligation' somewhere so that we later check that it's really
183 // implemented
184 // - both points go for additional requirements from where clauses as
185 // well (in fact, the 'implements' condition could just be considered a
186 // 'where Self: Trait' clause)
187 candidates.retain(|(t, _m)| {
188 let trait_ref = TraitRef { trait_: *t, substs: Substs::single(self.clone()) };
189 db.implements(trait_ref)
190 });
191 // FIXME if there's multiple candidates here, that's an ambiguity error
192 let (_chosen_trait, chosen_method) = candidates.first()?;
193 Some((self.clone(), *chosen_method))
137 } 194 }
138 195
139 // This would be nicer if it just returned an iterator, but that runs into 196 // This would be nicer if it just returned an iterator, but that runs into
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 3aedba243..655f3c522 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -1272,8 +1272,8 @@ fn test() {
1272[241; 252) 'Struct::FOO': u32 1272[241; 252) 'Struct::FOO': u32
1273[262; 263) 'y': u32 1273[262; 263) 'y': u32
1274[266; 275) 'Enum::BAR': u32 1274[266; 275) 'Enum::BAR': u32
1275[285; 286) 'z': u32 1275[285; 286) 'z': {unknown}
1276[289; 302) 'TraitTest::ID': u32"### 1276[289; 302) 'TraitTest::ID': {unknown}"###
1277 ); 1277 );
1278} 1278}
1279 1279
@@ -1918,9 +1918,9 @@ fn test() {
1918[110; 114) 'self': &{unknown} 1918[110; 114) 'self': &{unknown}
1919[170; 228) '{ ...i128 }': () 1919[170; 228) '{ ...i128 }': ()
1920[176; 178) 'S1': S1 1920[176; 178) 'S1': S1
1921[176; 187) 'S1.method()': {unknown} 1921[176; 187) 'S1.method()': u32
1922[203; 205) 'S2': S2 1922[203; 205) 'S2': S2
1923[203; 214) 'S2.method()': {unknown}"### 1923[203; 214) 'S2.method()': i128"###
1924 ); 1924 );
1925} 1925}
1926 1926
@@ -1964,10 +1964,10 @@ mod bar_test {
1964[169; 173) 'self': &{unknown} 1964[169; 173) 'self': &{unknown}
1965[300; 337) '{ ... }': () 1965[300; 337) '{ ... }': ()
1966[310; 311) 'S': S 1966[310; 311) 'S': S
1967[310; 320) 'S.method()': {unknown} 1967[310; 320) 'S.method()': u32
1968[416; 454) '{ ... }': () 1968[416; 454) '{ ... }': ()
1969[426; 427) 'S': S 1969[426; 427) 'S': S
1970[426; 436) 'S.method()': {unknown}"### 1970[426; 436) 'S.method()': i128"###
1971 ); 1971 );
1972} 1972}
1973 1973