diff options
Diffstat (limited to 'crates/hir_ty/src/method_resolution.rs')
-rw-r--r-- | crates/hir_ty/src/method_resolution.rs | 769 |
1 files changed, 769 insertions, 0 deletions
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs new file mode 100644 index 000000000..ec59145c7 --- /dev/null +++ b/crates/hir_ty/src/method_resolution.rs | |||
@@ -0,0 +1,769 @@ | |||
1 | //! This module is concerned with finding methods that a given type provides. | ||
2 | //! For details about how this works in rustc, see the method lookup page in the | ||
3 | //! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html) | ||
4 | //! and the corresponding code mostly in librustc_typeck/check/method/probe.rs. | ||
5 | use std::{iter, sync::Arc}; | ||
6 | |||
7 | use arrayvec::ArrayVec; | ||
8 | use base_db::CrateId; | ||
9 | use hir_def::{ | ||
10 | builtin_type::{IntBitness, Signedness}, | ||
11 | lang_item::LangItemTarget, | ||
12 | type_ref::Mutability, | ||
13 | AssocContainerId, AssocItemId, FunctionId, HasModule, ImplId, Lookup, TraitId, | ||
14 | }; | ||
15 | use hir_expand::name::Name; | ||
16 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
17 | |||
18 | use super::Substs; | ||
19 | use crate::{ | ||
20 | autoderef, | ||
21 | db::HirDatabase, | ||
22 | primitive::{FloatBitness, FloatTy, IntTy}, | ||
23 | utils::all_super_traits, | ||
24 | ApplicationTy, Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TyKind, | ||
25 | TypeCtor, TypeWalk, | ||
26 | }; | ||
27 | |||
28 | /// This is used as a key for indexing impls. | ||
29 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
30 | pub enum TyFingerprint { | ||
31 | Apply(TypeCtor), | ||
32 | } | ||
33 | |||
34 | impl TyFingerprint { | ||
35 | /// Creates a TyFingerprint for looking up an impl. Only certain types can | ||
36 | /// have impls: if we have some `struct S`, we can have an `impl S`, but not | ||
37 | /// `impl &S`. Hence, this will return `None` for reference types and such. | ||
38 | pub(crate) fn for_impl(ty: &Ty) -> Option<TyFingerprint> { | ||
39 | match ty { | ||
40 | Ty::Apply(a_ty) => Some(TyFingerprint::Apply(a_ty.ctor)), | ||
41 | _ => None, | ||
42 | } | ||
43 | } | ||
44 | } | ||
45 | |||
46 | pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [ | ||
47 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
48 | signedness: Signedness::Unsigned, | ||
49 | bitness: IntBitness::X8, | ||
50 | })), | ||
51 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
52 | signedness: Signedness::Unsigned, | ||
53 | bitness: IntBitness::X16, | ||
54 | })), | ||
55 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
56 | signedness: Signedness::Unsigned, | ||
57 | bitness: IntBitness::X32, | ||
58 | })), | ||
59 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
60 | signedness: Signedness::Unsigned, | ||
61 | bitness: IntBitness::X64, | ||
62 | })), | ||
63 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
64 | signedness: Signedness::Unsigned, | ||
65 | bitness: IntBitness::X128, | ||
66 | })), | ||
67 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
68 | signedness: Signedness::Unsigned, | ||
69 | bitness: IntBitness::Xsize, | ||
70 | })), | ||
71 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
72 | signedness: Signedness::Signed, | ||
73 | bitness: IntBitness::X8, | ||
74 | })), | ||
75 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
76 | signedness: Signedness::Signed, | ||
77 | bitness: IntBitness::X16, | ||
78 | })), | ||
79 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
80 | signedness: Signedness::Signed, | ||
81 | bitness: IntBitness::X32, | ||
82 | })), | ||
83 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
84 | signedness: Signedness::Signed, | ||
85 | bitness: IntBitness::X64, | ||
86 | })), | ||
87 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
88 | signedness: Signedness::Signed, | ||
89 | bitness: IntBitness::X128, | ||
90 | })), | ||
91 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
92 | signedness: Signedness::Signed, | ||
93 | bitness: IntBitness::Xsize, | ||
94 | })), | ||
95 | ]; | ||
96 | |||
97 | pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [ | ||
98 | TyFingerprint::Apply(TypeCtor::Float(FloatTy { bitness: FloatBitness::X32 })), | ||
99 | TyFingerprint::Apply(TypeCtor::Float(FloatTy { bitness: FloatBitness::X64 })), | ||
100 | ]; | ||
101 | |||
102 | /// Trait impls defined or available in some crate. | ||
103 | #[derive(Debug, Eq, PartialEq)] | ||
104 | pub struct TraitImpls { | ||
105 | // If the `Option<TyFingerprint>` is `None`, the impl may apply to any self type. | ||
106 | map: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>, | ||
107 | } | ||
108 | |||
109 | impl TraitImpls { | ||
110 | pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> { | ||
111 | let _p = profile::span("trait_impls_in_crate_query"); | ||
112 | let mut impls = Self { map: FxHashMap::default() }; | ||
113 | |||
114 | let crate_def_map = db.crate_def_map(krate); | ||
115 | for (_module_id, module_data) in crate_def_map.modules.iter() { | ||
116 | for impl_id in module_data.scope.impls() { | ||
117 | let target_trait = match db.impl_trait(impl_id) { | ||
118 | Some(tr) => tr.value.trait_, | ||
119 | None => continue, | ||
120 | }; | ||
121 | let self_ty = db.impl_self_ty(impl_id); | ||
122 | let self_ty_fp = TyFingerprint::for_impl(&self_ty.value); | ||
123 | impls | ||
124 | .map | ||
125 | .entry(target_trait) | ||
126 | .or_default() | ||
127 | .entry(self_ty_fp) | ||
128 | .or_default() | ||
129 | .push(impl_id); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | Arc::new(impls) | ||
134 | } | ||
135 | |||
136 | pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> { | ||
137 | let _p = profile::span("trait_impls_in_deps_query"); | ||
138 | let crate_graph = db.crate_graph(); | ||
139 | let mut res = Self { map: FxHashMap::default() }; | ||
140 | |||
141 | for krate in crate_graph.transitive_deps(krate) { | ||
142 | res.merge(&db.trait_impls_in_crate(krate)); | ||
143 | } | ||
144 | |||
145 | Arc::new(res) | ||
146 | } | ||
147 | |||
148 | fn merge(&mut self, other: &Self) { | ||
149 | for (trait_, other_map) in &other.map { | ||
150 | let map = self.map.entry(*trait_).or_default(); | ||
151 | for (fp, impls) in other_map { | ||
152 | let vec = map.entry(*fp).or_default(); | ||
153 | vec.extend(impls); | ||
154 | } | ||
155 | } | ||
156 | } | ||
157 | |||
158 | /// Queries all impls of the given trait. | ||
159 | pub fn for_trait(&self, trait_: TraitId) -> impl Iterator<Item = ImplId> + '_ { | ||
160 | self.map | ||
161 | .get(&trait_) | ||
162 | .into_iter() | ||
163 | .flat_map(|map| map.values().flat_map(|v| v.iter().copied())) | ||
164 | } | ||
165 | |||
166 | /// Queries all impls of `trait_` that may apply to `self_ty`. | ||
167 | pub fn for_trait_and_self_ty( | ||
168 | &self, | ||
169 | trait_: TraitId, | ||
170 | self_ty: TyFingerprint, | ||
171 | ) -> impl Iterator<Item = ImplId> + '_ { | ||
172 | self.map | ||
173 | .get(&trait_) | ||
174 | .into_iter() | ||
175 | .flat_map(move |map| map.get(&None).into_iter().chain(map.get(&Some(self_ty)))) | ||
176 | .flat_map(|v| v.iter().copied()) | ||
177 | } | ||
178 | |||
179 | pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ { | ||
180 | self.map.values().flat_map(|map| map.values().flat_map(|v| v.iter().copied())) | ||
181 | } | ||
182 | } | ||
183 | |||
184 | /// Inherent impls defined in some crate. | ||
185 | /// | ||
186 | /// Inherent impls can only be defined in the crate that also defines the self type of the impl | ||
187 | /// (note that some primitives are considered to be defined by both libcore and liballoc). | ||
188 | /// | ||
189 | /// This makes inherent impl lookup easier than trait impl lookup since we only have to consider a | ||
190 | /// single crate. | ||
191 | #[derive(Debug, Eq, PartialEq)] | ||
192 | pub struct InherentImpls { | ||
193 | map: FxHashMap<TyFingerprint, Vec<ImplId>>, | ||
194 | } | ||
195 | |||
196 | impl InherentImpls { | ||
197 | pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> { | ||
198 | let mut map: FxHashMap<_, Vec<_>> = FxHashMap::default(); | ||
199 | |||
200 | let crate_def_map = db.crate_def_map(krate); | ||
201 | for (_module_id, module_data) in crate_def_map.modules.iter() { | ||
202 | for impl_id in module_data.scope.impls() { | ||
203 | let data = db.impl_data(impl_id); | ||
204 | if data.target_trait.is_some() { | ||
205 | continue; | ||
206 | } | ||
207 | |||
208 | let self_ty = db.impl_self_ty(impl_id); | ||
209 | if let Some(fp) = TyFingerprint::for_impl(&self_ty.value) { | ||
210 | map.entry(fp).or_default().push(impl_id); | ||
211 | } | ||
212 | } | ||
213 | } | ||
214 | |||
215 | Arc::new(Self { map }) | ||
216 | } | ||
217 | |||
218 | pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] { | ||
219 | match TyFingerprint::for_impl(self_ty) { | ||
220 | Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]), | ||
221 | None => &[], | ||
222 | } | ||
223 | } | ||
224 | |||
225 | pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ { | ||
226 | self.map.values().flat_map(|v| v.iter().copied()) | ||
227 | } | ||
228 | } | ||
229 | |||
230 | impl Ty { | ||
231 | pub fn def_crates( | ||
232 | &self, | ||
233 | db: &dyn HirDatabase, | ||
234 | cur_crate: CrateId, | ||
235 | ) -> Option<ArrayVec<[CrateId; 2]>> { | ||
236 | // Types like slice can have inherent impls in several crates, (core and alloc). | ||
237 | // The corresponding impls are marked with lang items, so we can use them to find the required crates. | ||
238 | macro_rules! lang_item_crate { | ||
239 | ($($name:expr),+ $(,)?) => {{ | ||
240 | let mut v = ArrayVec::<[LangItemTarget; 2]>::new(); | ||
241 | $( | ||
242 | v.extend(db.lang_item(cur_crate, $name.into())); | ||
243 | )+ | ||
244 | v | ||
245 | }}; | ||
246 | } | ||
247 | |||
248 | let lang_item_targets = match self { | ||
249 | Ty::Apply(a_ty) => match a_ty.ctor { | ||
250 | TypeCtor::Adt(def_id) => { | ||
251 | return Some(std::iter::once(def_id.module(db.upcast()).krate).collect()) | ||
252 | } | ||
253 | TypeCtor::Bool => lang_item_crate!("bool"), | ||
254 | TypeCtor::Char => lang_item_crate!("char"), | ||
255 | TypeCtor::Float(f) => match f.bitness { | ||
256 | // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime) | ||
257 | FloatBitness::X32 => lang_item_crate!("f32", "f32_runtime"), | ||
258 | FloatBitness::X64 => lang_item_crate!("f64", "f64_runtime"), | ||
259 | }, | ||
260 | TypeCtor::Int(i) => lang_item_crate!(i.ty_to_string()), | ||
261 | TypeCtor::Str => lang_item_crate!("str_alloc", "str"), | ||
262 | TypeCtor::Slice => lang_item_crate!("slice_alloc", "slice"), | ||
263 | TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!("const_ptr"), | ||
264 | TypeCtor::RawPtr(Mutability::Mut) => lang_item_crate!("mut_ptr"), | ||
265 | _ => return None, | ||
266 | }, | ||
267 | _ => return None, | ||
268 | }; | ||
269 | let res = lang_item_targets | ||
270 | .into_iter() | ||
271 | .filter_map(|it| match it { | ||
272 | LangItemTarget::ImplDefId(it) => Some(it), | ||
273 | _ => None, | ||
274 | }) | ||
275 | .map(|it| it.lookup(db.upcast()).container.module(db.upcast()).krate) | ||
276 | .collect(); | ||
277 | Some(res) | ||
278 | } | ||
279 | } | ||
280 | /// Look up the method with the given name, returning the actual autoderefed | ||
281 | /// receiver type (but without autoref applied yet). | ||
282 | pub(crate) fn lookup_method( | ||
283 | ty: &Canonical<Ty>, | ||
284 | db: &dyn HirDatabase, | ||
285 | env: Arc<TraitEnvironment>, | ||
286 | krate: CrateId, | ||
287 | traits_in_scope: &FxHashSet<TraitId>, | ||
288 | name: &Name, | ||
289 | ) -> Option<(Ty, FunctionId)> { | ||
290 | iterate_method_candidates( | ||
291 | ty, | ||
292 | db, | ||
293 | env, | ||
294 | krate, | ||
295 | &traits_in_scope, | ||
296 | Some(name), | ||
297 | LookupMode::MethodCall, | ||
298 | |ty, f| match f { | ||
299 | AssocItemId::FunctionId(f) => Some((ty.clone(), f)), | ||
300 | _ => None, | ||
301 | }, | ||
302 | ) | ||
303 | } | ||
304 | |||
305 | /// Whether we're looking up a dotted method call (like `v.len()`) or a path | ||
306 | /// (like `Vec::new`). | ||
307 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
308 | pub enum LookupMode { | ||
309 | /// Looking up a method call like `v.len()`: We only consider candidates | ||
310 | /// that have a `self` parameter, and do autoderef. | ||
311 | MethodCall, | ||
312 | /// Looking up a path like `Vec::new` or `Vec::default`: We consider all | ||
313 | /// candidates including associated constants, but don't do autoderef. | ||
314 | Path, | ||
315 | } | ||
316 | |||
317 | // This would be nicer if it just returned an iterator, but that runs into | ||
318 | // lifetime problems, because we need to borrow temp `CrateImplDefs`. | ||
319 | // FIXME add a context type here? | ||
320 | pub fn iterate_method_candidates<T>( | ||
321 | ty: &Canonical<Ty>, | ||
322 | db: &dyn HirDatabase, | ||
323 | env: Arc<TraitEnvironment>, | ||
324 | krate: CrateId, | ||
325 | traits_in_scope: &FxHashSet<TraitId>, | ||
326 | name: Option<&Name>, | ||
327 | mode: LookupMode, | ||
328 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, | ||
329 | ) -> Option<T> { | ||
330 | let mut slot = None; | ||
331 | iterate_method_candidates_impl( | ||
332 | ty, | ||
333 | db, | ||
334 | env, | ||
335 | krate, | ||
336 | traits_in_scope, | ||
337 | name, | ||
338 | mode, | ||
339 | &mut |ty, item| { | ||
340 | assert!(slot.is_none()); | ||
341 | slot = callback(ty, item); | ||
342 | slot.is_some() | ||
343 | }, | ||
344 | ); | ||
345 | slot | ||
346 | } | ||
347 | |||
348 | fn iterate_method_candidates_impl( | ||
349 | ty: &Canonical<Ty>, | ||
350 | db: &dyn HirDatabase, | ||
351 | env: Arc<TraitEnvironment>, | ||
352 | krate: CrateId, | ||
353 | traits_in_scope: &FxHashSet<TraitId>, | ||
354 | name: Option<&Name>, | ||
355 | mode: LookupMode, | ||
356 | callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, | ||
357 | ) -> bool { | ||
358 | match mode { | ||
359 | LookupMode::MethodCall => { | ||
360 | // For method calls, rust first does any number of autoderef, and then one | ||
361 | // autoref (i.e. when the method takes &self or &mut self). We just ignore | ||
362 | // the autoref currently -- when we find a method matching the given name, | ||
363 | // we assume it fits. | ||
364 | |||
365 | // Also note that when we've got a receiver like &S, even if the method we | ||
366 | // find in the end takes &self, we still do the autoderef step (just as | ||
367 | // rustc does an autoderef and then autoref again). | ||
368 | let ty = InEnvironment { value: ty.clone(), environment: env.clone() }; | ||
369 | |||
370 | // We have to be careful about the order we're looking at candidates | ||
371 | // in here. Consider the case where we're resolving `x.clone()` | ||
372 | // where `x: &Vec<_>`. This resolves to the clone method with self | ||
373 | // type `Vec<_>`, *not* `&_`. I.e. we need to consider methods where | ||
374 | // the receiver type exactly matches before cases where we have to | ||
375 | // do autoref. But in the autoderef steps, the `&_` self type comes | ||
376 | // up *before* the `Vec<_>` self type. | ||
377 | // | ||
378 | // On the other hand, we don't want to just pick any by-value method | ||
379 | // before any by-autoref method; it's just that we need to consider | ||
380 | // the methods by autoderef order of *receiver types*, not *self | ||
381 | // types*. | ||
382 | |||
383 | let deref_chain = autoderef_method_receiver(db, krate, ty); | ||
384 | for i in 0..deref_chain.len() { | ||
385 | if iterate_method_candidates_with_autoref( | ||
386 | &deref_chain[i..], | ||
387 | db, | ||
388 | env.clone(), | ||
389 | krate, | ||
390 | traits_in_scope, | ||
391 | name, | ||
392 | callback, | ||
393 | ) { | ||
394 | return true; | ||
395 | } | ||
396 | } | ||
397 | false | ||
398 | } | ||
399 | LookupMode::Path => { | ||
400 | // No autoderef for path lookups | ||
401 | iterate_method_candidates_for_self_ty( | ||
402 | &ty, | ||
403 | db, | ||
404 | env, | ||
405 | krate, | ||
406 | traits_in_scope, | ||
407 | name, | ||
408 | callback, | ||
409 | ) | ||
410 | } | ||
411 | } | ||
412 | } | ||
413 | |||
414 | fn iterate_method_candidates_with_autoref( | ||
415 | deref_chain: &[Canonical<Ty>], | ||
416 | db: &dyn HirDatabase, | ||
417 | env: Arc<TraitEnvironment>, | ||
418 | krate: CrateId, | ||
419 | traits_in_scope: &FxHashSet<TraitId>, | ||
420 | name: Option<&Name>, | ||
421 | mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, | ||
422 | ) -> bool { | ||
423 | if iterate_method_candidates_by_receiver( | ||
424 | &deref_chain[0], | ||
425 | &deref_chain[1..], | ||
426 | db, | ||
427 | env.clone(), | ||
428 | krate, | ||
429 | &traits_in_scope, | ||
430 | name, | ||
431 | &mut callback, | ||
432 | ) { | ||
433 | return true; | ||
434 | } | ||
435 | let refed = Canonical { | ||
436 | kinds: deref_chain[0].kinds.clone(), | ||
437 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()), | ||
438 | }; | ||
439 | if iterate_method_candidates_by_receiver( | ||
440 | &refed, | ||
441 | deref_chain, | ||
442 | db, | ||
443 | env.clone(), | ||
444 | krate, | ||
445 | &traits_in_scope, | ||
446 | name, | ||
447 | &mut callback, | ||
448 | ) { | ||
449 | return true; | ||
450 | } | ||
451 | let ref_muted = Canonical { | ||
452 | kinds: deref_chain[0].kinds.clone(), | ||
453 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()), | ||
454 | }; | ||
455 | if iterate_method_candidates_by_receiver( | ||
456 | &ref_muted, | ||
457 | deref_chain, | ||
458 | db, | ||
459 | env, | ||
460 | krate, | ||
461 | &traits_in_scope, | ||
462 | name, | ||
463 | &mut callback, | ||
464 | ) { | ||
465 | return true; | ||
466 | } | ||
467 | false | ||
468 | } | ||
469 | |||
470 | fn iterate_method_candidates_by_receiver( | ||
471 | receiver_ty: &Canonical<Ty>, | ||
472 | rest_of_deref_chain: &[Canonical<Ty>], | ||
473 | db: &dyn HirDatabase, | ||
474 | env: Arc<TraitEnvironment>, | ||
475 | krate: CrateId, | ||
476 | traits_in_scope: &FxHashSet<TraitId>, | ||
477 | name: Option<&Name>, | ||
478 | mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, | ||
479 | ) -> bool { | ||
480 | // We're looking for methods with *receiver* type receiver_ty. These could | ||
481 | // be found in any of the derefs of receiver_ty, so we have to go through | ||
482 | // that. | ||
483 | for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { | ||
484 | if iterate_inherent_methods(self_ty, db, name, Some(receiver_ty), krate, &mut callback) { | ||
485 | return true; | ||
486 | } | ||
487 | } | ||
488 | for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { | ||
489 | if iterate_trait_method_candidates( | ||
490 | self_ty, | ||
491 | db, | ||
492 | env.clone(), | ||
493 | krate, | ||
494 | &traits_in_scope, | ||
495 | name, | ||
496 | Some(receiver_ty), | ||
497 | &mut callback, | ||
498 | ) { | ||
499 | return true; | ||
500 | } | ||
501 | } | ||
502 | false | ||
503 | } | ||
504 | |||
505 | fn iterate_method_candidates_for_self_ty( | ||
506 | self_ty: &Canonical<Ty>, | ||
507 | db: &dyn HirDatabase, | ||
508 | env: Arc<TraitEnvironment>, | ||
509 | krate: CrateId, | ||
510 | traits_in_scope: &FxHashSet<TraitId>, | ||
511 | name: Option<&Name>, | ||
512 | mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, | ||
513 | ) -> bool { | ||
514 | if iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) { | ||
515 | return true; | ||
516 | } | ||
517 | iterate_trait_method_candidates(self_ty, db, env, krate, traits_in_scope, name, None, callback) | ||
518 | } | ||
519 | |||
520 | fn iterate_trait_method_candidates( | ||
521 | self_ty: &Canonical<Ty>, | ||
522 | db: &dyn HirDatabase, | ||
523 | env: Arc<TraitEnvironment>, | ||
524 | krate: CrateId, | ||
525 | traits_in_scope: &FxHashSet<TraitId>, | ||
526 | name: Option<&Name>, | ||
527 | receiver_ty: Option<&Canonical<Ty>>, | ||
528 | callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, | ||
529 | ) -> bool { | ||
530 | // if ty is `dyn Trait`, the trait doesn't need to be in scope | ||
531 | let inherent_trait = | ||
532 | self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t)); | ||
533 | let env_traits = if let Ty::Placeholder(_) = self_ty.value { | ||
534 | // if we have `T: Trait` in the param env, the trait doesn't need to be in scope | ||
535 | env.trait_predicates_for_self_ty(&self_ty.value) | ||
536 | .map(|tr| tr.trait_) | ||
537 | .flat_map(|t| all_super_traits(db.upcast(), t)) | ||
538 | .collect() | ||
539 | } else { | ||
540 | Vec::new() | ||
541 | }; | ||
542 | let traits = | ||
543 | inherent_trait.chain(env_traits.into_iter()).chain(traits_in_scope.iter().copied()); | ||
544 | 'traits: for t in traits { | ||
545 | let data = db.trait_data(t); | ||
546 | |||
547 | // we'll be lazy about checking whether the type implements the | ||
548 | // trait, but if we find out it doesn't, we'll skip the rest of the | ||
549 | // iteration | ||
550 | let mut known_implemented = false; | ||
551 | for (_name, item) in data.items.iter() { | ||
552 | if !is_valid_candidate(db, name, receiver_ty, *item, self_ty) { | ||
553 | continue; | ||
554 | } | ||
555 | if !known_implemented { | ||
556 | let goal = generic_implements_goal(db, env.clone(), t, self_ty.clone()); | ||
557 | if db.trait_solve(krate, goal).is_none() { | ||
558 | continue 'traits; | ||
559 | } | ||
560 | } | ||
561 | known_implemented = true; | ||
562 | if callback(&self_ty.value, *item) { | ||
563 | return true; | ||
564 | } | ||
565 | } | ||
566 | } | ||
567 | false | ||
568 | } | ||
569 | |||
570 | fn iterate_inherent_methods( | ||
571 | self_ty: &Canonical<Ty>, | ||
572 | db: &dyn HirDatabase, | ||
573 | name: Option<&Name>, | ||
574 | receiver_ty: Option<&Canonical<Ty>>, | ||
575 | krate: CrateId, | ||
576 | callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, | ||
577 | ) -> bool { | ||
578 | let def_crates = match self_ty.value.def_crates(db, krate) { | ||
579 | Some(k) => k, | ||
580 | None => return false, | ||
581 | }; | ||
582 | for krate in def_crates { | ||
583 | let impls = db.inherent_impls_in_crate(krate); | ||
584 | |||
585 | for &impl_def in impls.for_self_ty(&self_ty.value) { | ||
586 | for &item in db.impl_data(impl_def).items.iter() { | ||
587 | if !is_valid_candidate(db, name, receiver_ty, item, self_ty) { | ||
588 | continue; | ||
589 | } | ||
590 | // we have to check whether the self type unifies with the type | ||
591 | // that the impl is for. If we have a receiver type, this | ||
592 | // already happens in `is_valid_candidate` above; if not, we | ||
593 | // check it here | ||
594 | if receiver_ty.is_none() && inherent_impl_substs(db, impl_def, self_ty).is_none() { | ||
595 | test_utils::mark::hit!(impl_self_type_match_without_receiver); | ||
596 | continue; | ||
597 | } | ||
598 | if callback(&self_ty.value, item) { | ||
599 | return true; | ||
600 | } | ||
601 | } | ||
602 | } | ||
603 | } | ||
604 | false | ||
605 | } | ||
606 | |||
607 | /// Returns the self type for the index trait call. | ||
608 | pub fn resolve_indexing_op( | ||
609 | db: &dyn HirDatabase, | ||
610 | ty: &Canonical<Ty>, | ||
611 | env: Arc<TraitEnvironment>, | ||
612 | krate: CrateId, | ||
613 | index_trait: TraitId, | ||
614 | ) -> Option<Canonical<Ty>> { | ||
615 | let ty = InEnvironment { value: ty.clone(), environment: env.clone() }; | ||
616 | let deref_chain = autoderef_method_receiver(db, krate, ty); | ||
617 | for ty in deref_chain { | ||
618 | let goal = generic_implements_goal(db, env.clone(), index_trait, ty.clone()); | ||
619 | if db.trait_solve(krate, goal).is_some() { | ||
620 | return Some(ty); | ||
621 | } | ||
622 | } | ||
623 | None | ||
624 | } | ||
625 | |||
626 | fn is_valid_candidate( | ||
627 | db: &dyn HirDatabase, | ||
628 | name: Option<&Name>, | ||
629 | receiver_ty: Option<&Canonical<Ty>>, | ||
630 | item: AssocItemId, | ||
631 | self_ty: &Canonical<Ty>, | ||
632 | ) -> bool { | ||
633 | match item { | ||
634 | AssocItemId::FunctionId(m) => { | ||
635 | let data = db.function_data(m); | ||
636 | if let Some(name) = name { | ||
637 | if &data.name != name { | ||
638 | return false; | ||
639 | } | ||
640 | } | ||
641 | if let Some(receiver_ty) = receiver_ty { | ||
642 | if !data.has_self_param { | ||
643 | return false; | ||
644 | } | ||
645 | let transformed_receiver_ty = match transform_receiver_ty(db, m, self_ty) { | ||
646 | Some(ty) => ty, | ||
647 | None => return false, | ||
648 | }; | ||
649 | if transformed_receiver_ty != receiver_ty.value { | ||
650 | return false; | ||
651 | } | ||
652 | } | ||
653 | true | ||
654 | } | ||
655 | AssocItemId::ConstId(c) => { | ||
656 | let data = db.const_data(c); | ||
657 | name.map_or(true, |name| data.name.as_ref() == Some(name)) && receiver_ty.is_none() | ||
658 | } | ||
659 | _ => false, | ||
660 | } | ||
661 | } | ||
662 | |||
663 | pub(crate) fn inherent_impl_substs( | ||
664 | db: &dyn HirDatabase, | ||
665 | impl_id: ImplId, | ||
666 | self_ty: &Canonical<Ty>, | ||
667 | ) -> Option<Substs> { | ||
668 | // we create a var for each type parameter of the impl; we need to keep in | ||
669 | // mind here that `self_ty` might have vars of its own | ||
670 | let vars = Substs::build_for_def(db, impl_id) | ||
671 | .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.kinds.len()) | ||
672 | .build(); | ||
673 | let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); | ||
674 | let mut kinds = self_ty.kinds.to_vec(); | ||
675 | kinds.extend(iter::repeat(TyKind::General).take(vars.len())); | ||
676 | let tys = Canonical { kinds: kinds.into(), value: (self_ty_with_vars, self_ty.value.clone()) }; | ||
677 | let substs = super::infer::unify(&tys); | ||
678 | // We only want the substs for the vars we added, not the ones from self_ty. | ||
679 | // Also, if any of the vars we added are still in there, we replace them by | ||
680 | // Unknown. I think this can only really happen if self_ty contained | ||
681 | // Unknown, and in that case we want the result to contain Unknown in those | ||
682 | // places again. | ||
683 | substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.kinds.len())) | ||
684 | } | ||
685 | |||
686 | /// This replaces any 'free' Bound vars in `s` (i.e. those with indices past | ||
687 | /// num_vars_to_keep) by `Ty::Unknown`. | ||
688 | fn fallback_bound_vars(s: Substs, num_vars_to_keep: usize) -> Substs { | ||
689 | s.fold_binders( | ||
690 | &mut |ty, binders| { | ||
691 | if let Ty::Bound(bound) = &ty { | ||
692 | if bound.index >= num_vars_to_keep && bound.debruijn >= binders { | ||
693 | Ty::Unknown | ||
694 | } else { | ||
695 | ty | ||
696 | } | ||
697 | } else { | ||
698 | ty | ||
699 | } | ||
700 | }, | ||
701 | DebruijnIndex::INNERMOST, | ||
702 | ) | ||
703 | } | ||
704 | |||
705 | fn transform_receiver_ty( | ||
706 | db: &dyn HirDatabase, | ||
707 | function_id: FunctionId, | ||
708 | self_ty: &Canonical<Ty>, | ||
709 | ) -> Option<Ty> { | ||
710 | let substs = match function_id.lookup(db.upcast()).container { | ||
711 | AssocContainerId::TraitId(_) => Substs::build_for_def(db, function_id) | ||
712 | .push(self_ty.value.clone()) | ||
713 | .fill_with_unknown() | ||
714 | .build(), | ||
715 | AssocContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty)?, | ||
716 | AssocContainerId::ContainerId(_) => unreachable!(), | ||
717 | }; | ||
718 | let sig = db.callable_item_signature(function_id.into()); | ||
719 | Some(sig.value.params()[0].clone().subst_bound_vars(&substs)) | ||
720 | } | ||
721 | |||
722 | pub fn implements_trait( | ||
723 | ty: &Canonical<Ty>, | ||
724 | db: &dyn HirDatabase, | ||
725 | env: Arc<TraitEnvironment>, | ||
726 | krate: CrateId, | ||
727 | trait_: TraitId, | ||
728 | ) -> bool { | ||
729 | let goal = generic_implements_goal(db, env, trait_, ty.clone()); | ||
730 | let solution = db.trait_solve(krate, goal); | ||
731 | |||
732 | solution.is_some() | ||
733 | } | ||
734 | |||
735 | /// This creates Substs for a trait with the given Self type and type variables | ||
736 | /// for all other parameters, to query Chalk with it. | ||
737 | fn generic_implements_goal( | ||
738 | db: &dyn HirDatabase, | ||
739 | env: Arc<TraitEnvironment>, | ||
740 | trait_: TraitId, | ||
741 | self_ty: Canonical<Ty>, | ||
742 | ) -> Canonical<InEnvironment<super::Obligation>> { | ||
743 | let mut kinds = self_ty.kinds.to_vec(); | ||
744 | let substs = super::Substs::build_for_def(db, trait_) | ||
745 | .push(self_ty.value) | ||
746 | .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len()) | ||
747 | .build(); | ||
748 | kinds.extend(iter::repeat(TyKind::General).take(substs.len() - 1)); | ||
749 | let trait_ref = TraitRef { trait_, substs }; | ||
750 | let obligation = super::Obligation::Trait(trait_ref); | ||
751 | Canonical { kinds: kinds.into(), value: InEnvironment::new(env, obligation) } | ||
752 | } | ||
753 | |||
754 | fn autoderef_method_receiver( | ||
755 | db: &dyn HirDatabase, | ||
756 | krate: CrateId, | ||
757 | ty: InEnvironment<Canonical<Ty>>, | ||
758 | ) -> Vec<Canonical<Ty>> { | ||
759 | let mut deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect(); | ||
760 | // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!) | ||
761 | if let Some(Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, parameters })) = | ||
762 | deref_chain.last().map(|ty| &ty.value) | ||
763 | { | ||
764 | let kinds = deref_chain.last().unwrap().kinds.clone(); | ||
765 | let unsized_ty = Ty::apply(TypeCtor::Slice, parameters.clone()); | ||
766 | deref_chain.push(Canonical { value: unsized_ty, kinds }) | ||
767 | } | ||
768 | deref_chain | ||
769 | } | ||