aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty/method_resolution.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ty/method_resolution.rs')
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs219
1 files changed, 109 insertions, 110 deletions
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index ea7da0b62..bc5033be6 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, infer::Canonical, Substs}; 19use super::{TraitRef, Canonical};
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)]
@@ -130,132 +130,123 @@ fn def_crate(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<Crate>
130 } 130 }
131} 131}
132 132
133impl Ty { 133/// Look up the method with the given name, returning the actual autoderefed
134 /// Look up the method with the given name, returning the actual autoderefed 134/// receiver type (but without autoref applied yet).
135 /// receiver type (but without autoref applied yet). 135pub(crate) fn lookup_method(
136 pub(crate) fn lookup_method( 136 ty: &Canonical<Ty>,
137 self, 137 db: &impl HirDatabase,
138 db: &impl HirDatabase, 138 name: &Name,
139 name: &Name, 139 resolver: &Resolver,
140 resolver: &Resolver, 140) -> Option<(Ty, Function)> {
141 ) -> Option<(Ty, Function)> { 141 iterate_method_candidates(ty, db, resolver, Some(name), |ty, f| Some((ty.clone(), f)))
142 self.iterate_method_candidates(db, resolver, Some(name), |ty, f| Some((ty.clone(), f))) 142}
143 }
144 143
145 // This would be nicer if it just returned an iterator, but that runs into 144// This would be nicer if it just returned an iterator, but that runs into
146 // lifetime problems, because we need to borrow temp `CrateImplBlocks`. 145// lifetime problems, because we need to borrow temp `CrateImplBlocks`.
147 pub(crate) fn iterate_method_candidates<T>( 146pub(crate) fn iterate_method_candidates<T>(
148 self, 147 ty: &Canonical<Ty>,
149 db: &impl HirDatabase, 148 db: &impl HirDatabase,
150 resolver: &Resolver, 149 resolver: &Resolver,
151 name: Option<&Name>, 150 name: Option<&Name>,
152 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 151 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
153 ) -> Option<T> { 152) -> Option<T> {
154 // For method calls, rust first does any number of autoderef, and then one 153 // For method calls, rust first does any number of autoderef, and then one
155 // autoref (i.e. when the method takes &self or &mut self). We just ignore 154 // autoref (i.e. when the method takes &self or &mut self). We just ignore
156 // the autoref currently -- when we find a method matching the given name, 155 // the autoref currently -- when we find a method matching the given name,
157 // we assume it fits. 156 // we assume it fits.
158 157
159 // Also note that when we've got a receiver like &S, even if the method we 158 // Also note that when we've got a receiver like &S, even if the method we
160 // find in the end takes &self, we still do the autoderef step (just as 159 // find in the end takes &self, we still do the autoderef step (just as
161 // rustc does an autoderef and then autoref again). 160 // rustc does an autoderef and then autoref again).
162 161
163 let krate = resolver.krate()?; 162 let krate = resolver.krate()?;
164 for derefed_ty in self.autoderef(db) { 163 for derefed_ty in ty.value.clone().autoderef(db) {
165 if let Some(result) = 164 let derefed_ty = Canonical { value: derefed_ty, num_vars: ty.num_vars };
166 derefed_ty.iterate_inherent_methods(db, name, krate, &mut callback) 165 if let Some(result) = iterate_inherent_methods(&derefed_ty, db, name, krate, &mut callback)
167 { 166 {
168 return Some(result); 167 return Some(result);
169 } 168 }
170 if let Some(result) = 169 if let Some(result) =
171 derefed_ty.iterate_trait_method_candidates(db, resolver, name, &mut callback) 170 iterate_trait_method_candidates(&derefed_ty, db, resolver, name, &mut callback)
172 { 171 {
173 return Some(result); 172 return Some(result);
174 }
175 } 173 }
176 None
177 } 174 }
175 None
176}
178 177
179 fn iterate_trait_method_candidates<T>( 178fn iterate_trait_method_candidates<T>(
180 &self, 179 ty: &Canonical<Ty>,
181 db: &impl HirDatabase, 180 db: &impl HirDatabase,
182 resolver: &Resolver, 181 resolver: &Resolver,
183 name: Option<&Name>, 182 name: Option<&Name>,
184 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 183 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
185 ) -> Option<T> { 184) -> Option<T> {
186 let krate = resolver.krate()?; 185 let krate = resolver.krate()?;
187 'traits: for t in resolver.traits_in_scope() { 186 'traits: for t in resolver.traits_in_scope() {
188 let data = t.trait_data(db); 187 let data = t.trait_data(db);
189 // we'll be lazy about checking whether the type implements the 188 // we'll be lazy about checking whether the type implements the
190 // trait, but if we find out it doesn't, we'll skip the rest of the 189 // trait, but if we find out it doesn't, we'll skip the rest of the
191 // iteration 190 // iteration
192 let mut known_implemented = false; 191 let mut known_implemented = false;
193 for item in data.items() { 192 for item in data.items() {
194 match item { 193 match item {
195 &TraitItem::Function(m) => { 194 &TraitItem::Function(m) => {
196 let sig = m.signature(db); 195 let sig = m.signature(db);
197 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() { 196 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() {
198 if !known_implemented { 197 if !known_implemented {
199 // TODO the self type may contain type 198 let trait_ref = canonical_trait_ref(db, t, ty.clone());
200 // variables, so we need to do proper 199 // FIXME cache this implements check (without solution) in a query?
201 // canonicalization here 200 if super::traits::implements(db, krate, trait_ref).is_none() {
202 let trait_ref = TraitRef { 201 continue 'traits;
203 trait_: t,
204 substs: fresh_substs_for_trait(db, t, self.clone()),
205 };
206 let canonical = Canonical {
207 num_vars: trait_ref.substs.len(),
208 value: trait_ref,
209 };
210 // FIXME cache this implements check (without solution) in a query?
211 if super::traits::implements(db, krate, canonical).is_none() {
212 continue 'traits;
213 }
214 }
215 known_implemented = true;
216 if let Some(result) = callback(self, m) {
217 return Some(result);
218 } 202 }
219 } 203 }
204 known_implemented = true;
205 // TODO the self type is now canonicalized...
206 if let Some(result) = callback(&ty.value, m) {
207 return Some(result);
208 }
220 } 209 }
221 _ => {}
222 } 210 }
211 _ => {}
223 } 212 }
224 } 213 }
225 None
226 } 214 }
215 None
216}
227 217
228 fn iterate_inherent_methods<T>( 218fn iterate_inherent_methods<T>(
229 &self, 219 ty: &Canonical<Ty>,
230 db: &impl HirDatabase, 220 db: &impl HirDatabase,
231 name: Option<&Name>, 221 name: Option<&Name>,
232 krate: Crate, 222 krate: Crate,
233 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 223 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
234 ) -> Option<T> { 224) -> Option<T> {
235 let krate = match def_crate(db, krate, self) { 225 let krate = match def_crate(db, krate, &ty.value) {
236 Some(krate) => krate, 226 Some(krate) => krate,
237 None => return None, 227 None => return None,
238 }; 228 };
239 let impls = db.impls_in_crate(krate); 229 let impls = db.impls_in_crate(krate);
240 230
241 for impl_block in impls.lookup_impl_blocks(self) { 231 for impl_block in impls.lookup_impl_blocks(&ty.value) {
242 for item in impl_block.items(db) { 232 for item in impl_block.items(db) {
243 match item { 233 match item {
244 ImplItem::Method(f) => { 234 ImplItem::Method(f) => {
245 let sig = f.signature(db); 235 let sig = f.signature(db);
246 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() { 236 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() {
247 if let Some(result) = callback(self, f) { 237 if let Some(result) = callback(&ty.value, f) {
248 return Some(result); 238 return Some(result);
249 }
250 } 239 }
251 } 240 }
252 _ => {}
253 } 241 }
242 _ => {}
254 } 243 }
255 } 244 }
256 None
257 } 245 }
246 None
247}
258 248
249impl Ty {
259 // This would be nicer if it just returned an iterator, but that runs into 250 // This would be nicer if it just returned an iterator, but that runs into
260 // lifetime problems, because we need to borrow temp `CrateImplBlocks`. 251 // lifetime problems, because we need to borrow temp `CrateImplBlocks`.
261 pub fn iterate_impl_items<T>( 252 pub fn iterate_impl_items<T>(
@@ -280,17 +271,25 @@ impl Ty {
280 271
281/// This creates Substs for a trait with the given Self type and type variables 272/// This creates Substs for a trait with the given Self type and type variables
282/// for all other parameters, to query Chalk with it. 273/// for all other parameters, to query Chalk with it.
283fn fresh_substs_for_trait(db: &impl HirDatabase, tr: Trait, self_ty: Ty) -> Substs { 274fn canonical_trait_ref(
275 db: &impl HirDatabase,
276 trait_: Trait,
277 self_ty: Canonical<Ty>,
278) -> Canonical<TraitRef> {
284 let mut substs = Vec::new(); 279 let mut substs = Vec::new();
285 let generics = tr.generic_params(db); 280 let generics = trait_.generic_params(db);
286 substs.push(self_ty); 281 let num_vars = self_ty.num_vars;
282 substs.push(self_ty.value);
287 substs.extend( 283 substs.extend(
288 generics 284 generics
289 .params_including_parent() 285 .params_including_parent()
290 .into_iter() 286 .into_iter()
291 .skip(1) 287 .skip(1)
292 .enumerate() 288 .enumerate()
293 .map(|(i, _p)| Ty::Bound(i as u32)), 289 .map(|(i, _p)| Ty::Bound((i + num_vars) as u32)),
294 ); 290 );
295 substs.into() 291 Canonical {
292 num_vars: substs.len() - 1 + self_ty.num_vars,
293 value: TraitRef { trait_, substs: substs.into() },
294 }
296} 295}