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