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.rs90
1 files changed, 67 insertions, 23 deletions
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index eb69344f6..ee0c7b00f 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -166,7 +166,19 @@ pub(crate) fn lookup_method(
166 name: &Name, 166 name: &Name,
167 resolver: &Resolver, 167 resolver: &Resolver,
168) -> Option<(Ty, Function)> { 168) -> Option<(Ty, Function)> {
169 iterate_method_candidates(ty, db, resolver, Some(name), |ty, f| Some((ty.clone(), f))) 169 iterate_method_candidates(ty, db, resolver, Some(name), LookupMode::MethodCall, |ty, f| {
170 if let AssocItem::Function(f) = f {
171 Some((ty.clone(), f))
172 } else {
173 None
174 }
175 })
176}
177
178#[derive(Copy, Clone, Debug, PartialEq, Eq)]
179pub(crate) enum LookupMode {
180 MethodCall,
181 Path,
170} 182}
171 183
172// This would be nicer if it just returned an iterator, but that runs into 184// This would be nicer if it just returned an iterator, but that runs into
@@ -176,7 +188,8 @@ pub(crate) fn iterate_method_candidates<T>(
176 db: &impl HirDatabase, 188 db: &impl HirDatabase,
177 resolver: &Resolver, 189 resolver: &Resolver,
178 name: Option<&Name>, 190 name: Option<&Name>,
179 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 191 mode: LookupMode,
192 mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
180) -> Option<T> { 193) -> Option<T> {
181 // For method calls, rust first does any number of autoderef, and then one 194 // For method calls, rust first does any number of autoderef, and then one
182 // autoref (i.e. when the method takes &self or &mut self). We just ignore 195 // autoref (i.e. when the method takes &self or &mut self). We just ignore
@@ -188,13 +201,15 @@ pub(crate) fn iterate_method_candidates<T>(
188 // rustc does an autoderef and then autoref again). 201 // rustc does an autoderef and then autoref again).
189 202
190 let krate = resolver.krate()?; 203 let krate = resolver.krate()?;
204 // TODO no autoderef in LookupMode::Path
191 for derefed_ty in autoderef::autoderef(db, resolver, ty.clone()) { 205 for derefed_ty in autoderef::autoderef(db, resolver, ty.clone()) {
192 if let Some(result) = iterate_inherent_methods(&derefed_ty, db, name, krate, &mut callback) 206 if let Some(result) =
207 iterate_inherent_methods(&derefed_ty, db, name, mode, krate, &mut callback)
193 { 208 {
194 return Some(result); 209 return Some(result);
195 } 210 }
196 if let Some(result) = 211 if let Some(result) =
197 iterate_trait_method_candidates(&derefed_ty, db, resolver, name, &mut callback) 212 iterate_trait_method_candidates(&derefed_ty, db, resolver, name, mode, &mut callback)
198 { 213 {
199 return Some(result); 214 return Some(result);
200 } 215 }
@@ -207,7 +222,8 @@ fn iterate_trait_method_candidates<T>(
207 db: &impl HirDatabase, 222 db: &impl HirDatabase,
208 resolver: &Resolver, 223 resolver: &Resolver,
209 name: Option<&Name>, 224 name: Option<&Name>,
210 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 225 mode: LookupMode,
226 mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
211) -> Option<T> { 227) -> Option<T> {
212 let krate = resolver.krate()?; 228 let krate = resolver.krate()?;
213 // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) 229 // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that)
@@ -231,21 +247,35 @@ fn iterate_trait_method_candidates<T>(
231 // trait, but if we find out it doesn't, we'll skip the rest of the 247 // trait, but if we find out it doesn't, we'll skip the rest of the
232 // iteration 248 // iteration
233 let mut known_implemented = inherently_implemented; 249 let mut known_implemented = inherently_implemented;
234 for item in data.items() { 250 for &item in data.items() {
235 if let AssocItem::Function(m) = *item { 251 // TODO unify with the impl case
236 let data = m.data(db); 252 match item {
237 if name.map_or(true, |name| data.name() == name) && data.has_self_param() { 253 AssocItem::Function(m) => {
238 if !known_implemented { 254 let data = m.data(db);
239 let goal = generic_implements_goal(db, env.clone(), t, ty.clone()); 255 if !name.map_or(true, |name| data.name() == name)
240 if db.trait_solve(krate, goal).is_none() { 256 || (!data.has_self_param() && mode != LookupMode::Path)
241 continue 'traits; 257 {
242 } 258 continue;
243 } 259 }
244 known_implemented = true; 260 }
245 if let Some(result) = callback(&ty.value, m) { 261 AssocItem::Const(c) => {
246 return Some(result); 262 if !name.map_or(true, |name| Some(name) == c.name(db).as_ref())
263 || (mode != LookupMode::Path)
264 {
265 continue;
247 } 266 }
248 } 267 }
268 _ => {}
269 };
270 if !known_implemented {
271 let goal = generic_implements_goal(db, env.clone(), t, ty.clone());
272 if db.trait_solve(krate, goal).is_none() {
273 continue 'traits;
274 }
275 }
276 known_implemented = true;
277 if let Some(result) = callback(&ty.value, item) {
278 return Some(result);
249 } 279 }
250 } 280 }
251 } 281 }
@@ -256,21 +286,35 @@ fn iterate_inherent_methods<T>(
256 ty: &Canonical<Ty>, 286 ty: &Canonical<Ty>,
257 db: &impl HirDatabase, 287 db: &impl HirDatabase,
258 name: Option<&Name>, 288 name: Option<&Name>,
289 mode: LookupMode,
259 krate: Crate, 290 krate: Crate,
260 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 291 mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
261) -> Option<T> { 292) -> Option<T> {
262 for krate in def_crates(db, krate, &ty.value)? { 293 for krate in def_crates(db, krate, &ty.value)? {
263 let impls = db.impls_in_crate(krate); 294 let impls = db.impls_in_crate(krate);
264 295
265 for impl_block in impls.lookup_impl_blocks(&ty.value) { 296 for impl_block in impls.lookup_impl_blocks(&ty.value) {
266 for item in impl_block.items(db) { 297 for item in impl_block.items(db) {
267 if let AssocItem::Function(f) = item { 298 match item {
268 let data = f.data(db); 299 AssocItem::Function(f) => {
269 if name.map_or(true, |name| data.name() == name) && data.has_self_param() { 300 let data = f.data(db);
270 if let Some(result) = callback(&ty.value, f) { 301 if !name.map_or(true, |name| data.name() == name)
271 return Some(result); 302 || (!data.has_self_param() && mode != LookupMode::Path)
303 {
304 continue;
272 } 305 }
273 } 306 }
307 AssocItem::Const(c) => {
308 if !name.map_or(true, |name| Some(name) == c.name(db).as_ref())
309 || (mode != LookupMode::Path)
310 {
311 continue;
312 }
313 }
314 _ => {}
315 }
316 if let Some(result) = callback(&ty.value, item) {
317 return Some(result);
274 } 318 }
275 } 319 }
276 } 320 }