diff options
Diffstat (limited to 'crates/ra_hir/src/ty/method_resolution.rs')
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 129 |
1 files changed, 53 insertions, 76 deletions
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index f1bc638ee..92645e2a5 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -6,9 +6,10 @@ use std::sync::Arc; | |||
6 | 6 | ||
7 | use arrayvec::ArrayVec; | 7 | use arrayvec::ArrayVec; |
8 | use hir_def::{ | 8 | use hir_def::{ |
9 | lang_item::LangItemTarget, resolver::HasResolver, resolver::Resolver, AssocItemId, AstItemDef, | 9 | lang_item::LangItemTarget, resolver::HasResolver, resolver::Resolver, type_ref::Mutability, |
10 | HasModule, ImplId, TraitId, | 10 | AssocItemId, AstItemDef, HasModule, ImplId, TraitId, |
11 | }; | 11 | }; |
12 | use hir_expand::name::Name; | ||
12 | use ra_db::CrateId; | 13 | use ra_db::CrateId; |
13 | use ra_prof::profile; | 14 | use ra_prof::profile; |
14 | use rustc_hash::FxHashMap; | 15 | use rustc_hash::FxHashMap; |
@@ -17,7 +18,7 @@ use crate::{ | |||
17 | db::HirDatabase, | 18 | db::HirDatabase, |
18 | ty::primitive::{FloatBitness, Uncertain}, | 19 | ty::primitive::{FloatBitness, Uncertain}, |
19 | ty::{utils::all_super_traits, Ty, TypeCtor}, | 20 | ty::{utils::all_super_traits, Ty, TypeCtor}, |
20 | AssocItem, Crate, Function, Mutability, Name, Trait, | 21 | AssocItem, Function, |
21 | }; | 22 | }; |
22 | 23 | ||
23 | use super::{autoderef, Canonical, InEnvironment, TraitEnvironment, TraitRef}; | 24 | use super::{autoderef, Canonical, InEnvironment, TraitEnvironment, TraitRef}; |
@@ -87,8 +88,8 @@ impl CrateImplBlocks { | |||
87 | fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flatten().copied() | 88 | fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flatten().copied() |
88 | } | 89 | } |
89 | 90 | ||
90 | pub fn lookup_impl_blocks_for_trait(&self, tr: Trait) -> impl Iterator<Item = ImplId> + '_ { | 91 | pub fn lookup_impl_blocks_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ { |
91 | self.impls_by_trait.get(&tr.id).into_iter().flatten().copied() | 92 | self.impls_by_trait.get(&tr).into_iter().flatten().copied() |
92 | } | 93 | } |
93 | 94 | ||
94 | pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a { | 95 | pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a { |
@@ -96,51 +97,56 @@ impl CrateImplBlocks { | |||
96 | } | 97 | } |
97 | } | 98 | } |
98 | 99 | ||
99 | fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayVec<[Crate; 2]>> { | 100 | impl Ty { |
100 | // Types like slice can have inherent impls in several crates, (core and alloc). | 101 | pub(crate) fn def_crates( |
101 | // The corresponding impls are marked with lang items, so we can use them to find the required crates. | 102 | &self, |
102 | macro_rules! lang_item_crate { | 103 | db: &impl HirDatabase, |
104 | cur_crate: CrateId, | ||
105 | ) -> Option<ArrayVec<[CrateId; 2]>> { | ||
106 | // Types like slice can have inherent impls in several crates, (core and alloc). | ||
107 | // The corresponding impls are marked with lang items, so we can use them to find the required crates. | ||
108 | macro_rules! lang_item_crate { | ||
103 | ($($name:expr),+ $(,)?) => {{ | 109 | ($($name:expr),+ $(,)?) => {{ |
104 | let mut v = ArrayVec::<[LangItemTarget; 2]>::new(); | 110 | let mut v = ArrayVec::<[LangItemTarget; 2]>::new(); |
105 | $( | 111 | $( |
106 | v.extend(db.lang_item(cur_crate.crate_id, $name.into())); | 112 | v.extend(db.lang_item(cur_crate, $name.into())); |
107 | )+ | 113 | )+ |
108 | v | 114 | v |
109 | }}; | 115 | }}; |
110 | } | 116 | } |
111 | 117 | ||
112 | let lang_item_targets = match ty { | 118 | let lang_item_targets = match self { |
113 | Ty::Apply(a_ty) => match a_ty.ctor { | 119 | Ty::Apply(a_ty) => match a_ty.ctor { |
114 | TypeCtor::Adt(def_id) => { | 120 | TypeCtor::Adt(def_id) => { |
115 | return Some(std::iter::once(def_id.module(db).krate.into()).collect()) | 121 | return Some(std::iter::once(def_id.module(db).krate).collect()) |
116 | } | 122 | } |
117 | TypeCtor::Bool => lang_item_crate!("bool"), | 123 | TypeCtor::Bool => lang_item_crate!("bool"), |
118 | TypeCtor::Char => lang_item_crate!("char"), | 124 | TypeCtor::Char => lang_item_crate!("char"), |
119 | TypeCtor::Float(Uncertain::Known(f)) => match f.bitness { | 125 | TypeCtor::Float(Uncertain::Known(f)) => match f.bitness { |
120 | // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime) | 126 | // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime) |
121 | FloatBitness::X32 => lang_item_crate!("f32", "f32_runtime"), | 127 | FloatBitness::X32 => lang_item_crate!("f32", "f32_runtime"), |
122 | FloatBitness::X64 => lang_item_crate!("f64", "f64_runtime"), | 128 | FloatBitness::X64 => lang_item_crate!("f64", "f64_runtime"), |
129 | }, | ||
130 | TypeCtor::Int(Uncertain::Known(i)) => lang_item_crate!(i.ty_to_string()), | ||
131 | TypeCtor::Str => lang_item_crate!("str_alloc", "str"), | ||
132 | TypeCtor::Slice => lang_item_crate!("slice_alloc", "slice"), | ||
133 | TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!("const_ptr"), | ||
134 | TypeCtor::RawPtr(Mutability::Mut) => lang_item_crate!("mut_ptr"), | ||
135 | _ => return None, | ||
123 | }, | 136 | }, |
124 | TypeCtor::Int(Uncertain::Known(i)) => lang_item_crate!(i.ty_to_string()), | ||
125 | TypeCtor::Str => lang_item_crate!("str_alloc", "str"), | ||
126 | TypeCtor::Slice => lang_item_crate!("slice_alloc", "slice"), | ||
127 | TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!("const_ptr"), | ||
128 | TypeCtor::RawPtr(Mutability::Mut) => lang_item_crate!("mut_ptr"), | ||
129 | _ => return None, | 137 | _ => return None, |
130 | }, | 138 | }; |
131 | _ => return None, | 139 | let res = lang_item_targets |
132 | }; | 140 | .into_iter() |
133 | let res = lang_item_targets | 141 | .filter_map(|it| match it { |
134 | .into_iter() | 142 | LangItemTarget::ImplBlockId(it) => Some(it), |
135 | .filter_map(|it| match it { | 143 | _ => None, |
136 | LangItemTarget::ImplBlockId(it) => Some(it), | 144 | }) |
137 | _ => None, | 145 | .map(|it| it.module(db).krate) |
138 | }) | 146 | .collect(); |
139 | .map(|it| it.module(db).krate.into()) | 147 | Some(res) |
140 | .collect(); | 148 | } |
141 | Some(res) | ||
142 | } | 149 | } |
143 | |||
144 | /// Look up the method with the given name, returning the actual autoderefed | 150 | /// Look up the method with the given name, returning the actual autoderefed |
145 | /// receiver type (but without autoref applied yet). | 151 | /// receiver type (but without autoref applied yet). |
146 | pub(crate) fn lookup_method( | 152 | pub(crate) fn lookup_method( |
@@ -193,14 +199,9 @@ pub(crate) fn iterate_method_candidates<T>( | |||
193 | let environment = TraitEnvironment::lower(db, resolver); | 199 | let environment = TraitEnvironment::lower(db, resolver); |
194 | let ty = InEnvironment { value: ty.clone(), environment }; | 200 | let ty = InEnvironment { value: ty.clone(), environment }; |
195 | for derefed_ty in autoderef::autoderef(db, resolver.krate(), ty) { | 201 | for derefed_ty in autoderef::autoderef(db, resolver.krate(), ty) { |
196 | if let Some(result) = iterate_inherent_methods( | 202 | if let Some(result) = |
197 | &derefed_ty, | 203 | iterate_inherent_methods(&derefed_ty, db, name, mode, krate, &mut callback) |
198 | db, | 204 | { |
199 | name, | ||
200 | mode, | ||
201 | krate.into(), | ||
202 | &mut callback, | ||
203 | ) { | ||
204 | return Some(result); | 205 | return Some(result); |
205 | } | 206 | } |
206 | if let Some(result) = iterate_trait_method_candidates( | 207 | if let Some(result) = iterate_trait_method_candidates( |
@@ -283,11 +284,11 @@ fn iterate_inherent_methods<T>( | |||
283 | db: &impl HirDatabase, | 284 | db: &impl HirDatabase, |
284 | name: Option<&Name>, | 285 | name: Option<&Name>, |
285 | mode: LookupMode, | 286 | mode: LookupMode, |
286 | krate: Crate, | 287 | krate: CrateId, |
287 | mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, | 288 | mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, |
288 | ) -> Option<T> { | 289 | ) -> Option<T> { |
289 | for krate in def_crates(db, krate, &ty.value)? { | 290 | for krate in ty.value.def_crates(db, krate)? { |
290 | let impls = db.impls_in_crate(krate.crate_id); | 291 | let impls = db.impls_in_crate(krate); |
291 | 292 | ||
292 | for impl_block in impls.lookup_impl_blocks(&ty.value) { | 293 | for impl_block in impls.lookup_impl_blocks(&ty.value) { |
293 | for &item in db.impl_data(impl_block).items.iter() { | 294 | for &item in db.impl_data(impl_block).items.iter() { |
@@ -327,7 +328,7 @@ pub(crate) fn implements_trait( | |||
327 | ty: &Canonical<Ty>, | 328 | ty: &Canonical<Ty>, |
328 | db: &impl HirDatabase, | 329 | db: &impl HirDatabase, |
329 | resolver: &Resolver, | 330 | resolver: &Resolver, |
330 | krate: Crate, | 331 | krate: CrateId, |
331 | trait_: TraitId, | 332 | trait_: TraitId, |
332 | ) -> bool { | 333 | ) -> bool { |
333 | if ty.value.inherent_trait() == Some(trait_) { | 334 | if ty.value.inherent_trait() == Some(trait_) { |
@@ -337,35 +338,11 @@ pub(crate) fn implements_trait( | |||
337 | } | 338 | } |
338 | let env = TraitEnvironment::lower(db, resolver); | 339 | let env = TraitEnvironment::lower(db, resolver); |
339 | let goal = generic_implements_goal(db, env, trait_, ty.clone()); | 340 | let goal = generic_implements_goal(db, env, trait_, ty.clone()); |
340 | let solution = db.trait_solve(krate, goal); | 341 | let solution = db.trait_solve(krate.into(), goal); |
341 | 342 | ||
342 | solution.is_some() | 343 | solution.is_some() |
343 | } | 344 | } |
344 | 345 | ||
345 | impl Ty { | ||
346 | // This would be nicer if it just returned an iterator, but that runs into | ||
347 | // lifetime problems, because we need to borrow temp `CrateImplBlocks`. | ||
348 | pub fn iterate_impl_items<T>( | ||
349 | self, | ||
350 | db: &impl HirDatabase, | ||
351 | krate: Crate, | ||
352 | mut callback: impl FnMut(AssocItem) -> Option<T>, | ||
353 | ) -> Option<T> { | ||
354 | for krate in def_crates(db, krate, &self)? { | ||
355 | let impls = db.impls_in_crate(krate.crate_id); | ||
356 | |||
357 | for impl_block in impls.lookup_impl_blocks(&self) { | ||
358 | for &item in db.impl_data(impl_block).items.iter() { | ||
359 | if let Some(result) = callback(item.into()) { | ||
360 | return Some(result); | ||
361 | } | ||
362 | } | ||
363 | } | ||
364 | } | ||
365 | None | ||
366 | } | ||
367 | } | ||
368 | |||
369 | /// This creates Substs for a trait with the given Self type and type variables | 346 | /// This creates Substs for a trait with the given Self type and type variables |
370 | /// for all other parameters, to query Chalk with it. | 347 | /// for all other parameters, to query Chalk with it. |
371 | fn generic_implements_goal( | 348 | fn generic_implements_goal( |