diff options
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r-- | crates/ra_hir/src/ty/infer/path.rs | 135 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 90 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 4 |
3 files changed, 96 insertions, 133 deletions
diff --git a/crates/ra_hir/src/ty/infer/path.rs b/crates/ra_hir/src/ty/infer/path.rs index c58564b22..1946bf608 100644 --- a/crates/ra_hir/src/ty/infer/path.rs +++ b/crates/ra_hir/src/ty/infer/path.rs | |||
@@ -6,11 +6,9 @@ use super::{ExprOrPatId, InferenceContext, TraitRef}; | |||
6 | use crate::{ | 6 | use crate::{ |
7 | db::HirDatabase, | 7 | db::HirDatabase, |
8 | resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, | 8 | resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, |
9 | ty::{lower, traits::TraitEnvironment, Canonical}, | 9 | ty::{method_resolution, Substs, Ty, TypableDef, TypeWalk}, |
10 | ty::{Substs, Ty, TypableDef, TypeWalk}, | 10 | AssocItem, Container, HasGenericParams, Name, Namespace, Path, |
11 | AssocItem, HasGenericParams, Name, Namespace, Path, Trait, | ||
12 | }; | 11 | }; |
13 | use std::sync::Arc; | ||
14 | 12 | ||
15 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 13 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
16 | pub(super) fn infer_path( | 14 | pub(super) fn infer_path( |
@@ -184,91 +182,34 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
184 | return None; | 182 | return None; |
185 | } | 183 | } |
186 | 184 | ||
187 | self.find_inherent_assoc_candidate(ty.clone(), name, id) | ||
188 | .or_else(|| self.find_trait_assoc_candidate(ty.clone(), name, id)) | ||
189 | } | ||
190 | |||
191 | fn find_inherent_assoc_candidate( | ||
192 | &mut self, | ||
193 | ty: Ty, | ||
194 | name: &Name, | ||
195 | id: ExprOrPatId, | ||
196 | ) -> Option<(ValueNs, Option<Substs>)> { | ||
197 | let krate = self.resolver.krate()?; | ||
198 | |||
199 | // Find impl | ||
200 | let item = ty.clone().iterate_impl_items(self.db, krate, |item| match item { | ||
201 | AssocItem::Function(func) => { | ||
202 | if *name == func.name(self.db) { | ||
203 | Some(AssocItem::Function(func)) | ||
204 | } else { | ||
205 | None | ||
206 | } | ||
207 | } | ||
208 | |||
209 | AssocItem::Const(konst) => { | ||
210 | if konst.name(self.db).map_or(false, |n| n == *name) { | ||
211 | Some(AssocItem::Const(konst)) | ||
212 | } else { | ||
213 | None | ||
214 | } | ||
215 | } | ||
216 | AssocItem::TypeAlias(_) => None, | ||
217 | })?; | ||
218 | let def = match item { | ||
219 | AssocItem::Function(f) => ValueNs::Function(f), | ||
220 | AssocItem::Const(c) => ValueNs::Const(c), | ||
221 | AssocItem::TypeAlias(_) => unreachable!(), | ||
222 | }; | ||
223 | let substs = self.find_self_types(&def, ty); | ||
224 | |||
225 | self.write_assoc_resolution(id, item); | ||
226 | Some((def, substs)) | ||
227 | } | ||
228 | |||
229 | fn find_trait_assoc_candidate( | ||
230 | &mut self, | ||
231 | ty: Ty, | ||
232 | name: &Name, | ||
233 | id: ExprOrPatId, | ||
234 | ) -> Option<(ValueNs, Option<Substs>)> { | ||
235 | let krate = self.resolver.krate()?; | ||
236 | |||
237 | let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); | 185 | let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); |
238 | 186 | ||
239 | let env = lower::trait_env(self.db, &self.resolver); | 187 | method_resolution::iterate_method_candidates( |
240 | // if we have `T: Trait` in the param env, the trait doesn't need to be in scope | 188 | &canonical_ty.value, |
241 | let traits_from_env = env | 189 | self.db, |
242 | .trait_predicates_for_self_ty(&ty) | 190 | &self.resolver.clone(), |
243 | .map(|tr| tr.trait_) | 191 | Some(name), |
244 | .flat_map(|t| t.all_super_traits(self.db)); | 192 | method_resolution::LookupMode::Path, |
245 | let traits = traits_from_env.chain(self.resolver.traits_in_scope(self.db)); | 193 | move |_ty, item| { |
246 | 194 | let def = match item { | |
247 | 'traits: for t in traits { | 195 | AssocItem::Function(f) => ValueNs::Function(f), |
248 | let data = t.trait_data(self.db); | 196 | AssocItem::Const(c) => ValueNs::Const(c), |
249 | let mut known_implemented = false; | 197 | AssocItem::TypeAlias(_) => unreachable!(), |
250 | for item in data.items() { | 198 | }; |
251 | if let AssocItem::Function(f) = *item { | 199 | match item.container(self.db) { |
252 | if f.name(self.db) == *name { | 200 | Container::ImplBlock(_) => { |
253 | if !known_implemented { | 201 | let substs = self.find_self_types(&def, ty.clone()); |
254 | let goal = generic_implements_goal( | 202 | |
255 | self.db, | 203 | self.write_assoc_resolution(id, item); |
256 | env.clone(), | 204 | Some((def, substs)) |
257 | t, | 205 | } |
258 | canonical_ty.value.clone(), | 206 | Container::Trait(t) => { |
259 | ); | ||
260 | if self.db.trait_solve(krate, goal).is_none() { | ||
261 | continue 'traits; | ||
262 | } | ||
263 | } | ||
264 | known_implemented = true; | ||
265 | |||
266 | // we're picking this method | 207 | // we're picking this method |
267 | let trait_substs = Substs::build_for_def(self.db, t) | 208 | let trait_substs = Substs::build_for_def(self.db, t) |
268 | .push(ty.clone()) | 209 | .push(ty.clone()) |
269 | .fill(std::iter::repeat_with(|| self.new_type_var())) | 210 | .fill(std::iter::repeat_with(|| self.new_type_var())) |
270 | .build(); | 211 | .build(); |
271 | let substs = Substs::build_for_def(self.db, f) | 212 | let substs = Substs::build_for_def(self.db, item) |
272 | .use_parent_substs(&trait_substs) | 213 | .use_parent_substs(&trait_substs) |
273 | .fill_with_params() | 214 | .fill_with_params() |
274 | .build(); | 215 | .build(); |
@@ -277,14 +218,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
277 | substs: trait_substs, | 218 | substs: trait_substs, |
278 | })); | 219 | })); |
279 | 220 | ||
280 | self.write_assoc_resolution(id, *item); | 221 | self.write_assoc_resolution(id, item); |
281 | return Some((ValueNs::Function(f), Some(substs))); | 222 | Some((def, Some(substs))) |
282 | } | 223 | } |
283 | } | 224 | } |
284 | } | 225 | }, |
285 | } | 226 | ) |
286 | |||
287 | None | ||
288 | } | 227 | } |
289 | 228 | ||
290 | fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { | 229 | fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { |
@@ -317,23 +256,3 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
317 | } | 256 | } |
318 | } | 257 | } |
319 | } | 258 | } |
320 | |||
321 | // TODO remove duplication | ||
322 | /// This creates Substs for a trait with the given Self type and type variables | ||
323 | /// for all other parameters, to query Chalk with it. | ||
324 | fn generic_implements_goal( | ||
325 | db: &impl HirDatabase, | ||
326 | env: Arc<TraitEnvironment>, | ||
327 | trait_: Trait, | ||
328 | self_ty: Canonical<Ty>, | ||
329 | ) -> Canonical<super::InEnvironment<super::Obligation>> { | ||
330 | let num_vars = self_ty.num_vars; | ||
331 | let substs = super::Substs::build_for_def(db, trait_) | ||
332 | .push(self_ty.value) | ||
333 | .fill_with_bound_vars(num_vars as u32) | ||
334 | .build(); | ||
335 | let num_vars = substs.len() - 1 + self_ty.num_vars; | ||
336 | let trait_ref = TraitRef { trait_, substs }; | ||
337 | let obligation = super::Obligation::Trait(trait_ref); | ||
338 | Canonical { num_vars, value: super::InEnvironment::new(env, obligation) } | ||
339 | } | ||
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)] | ||
179 | pub(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 | } |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index e071e4d4e..bfef48b16 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -1841,8 +1841,8 @@ fn test() { | |||
1841 | [243; 254) 'Struct::FOO': u32 | 1841 | [243; 254) 'Struct::FOO': u32 |
1842 | [264; 265) 'y': u32 | 1842 | [264; 265) 'y': u32 |
1843 | [268; 277) 'Enum::BAR': u32 | 1843 | [268; 277) 'Enum::BAR': u32 |
1844 | [287; 288) 'z': {unknown} | 1844 | [287; 288) 'z': u32 |
1845 | [291; 304) 'TraitTest::ID': {unknown} | 1845 | [291; 304) 'TraitTest::ID': u32 |
1846 | "### | 1846 | "### |
1847 | ); | 1847 | ); |
1848 | } | 1848 | } |