diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-11-01 19:03:05 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2019-11-01 19:03:05 +0000 |
commit | 9db97820f4c1c38110175f4efda2702356a4199a (patch) | |
tree | f560ab731b9da35902d3da720e19731b51ab62df /crates/ra_hir/src | |
parent | ed5212e1ac71e959d802a9a7ad28d06c8b18e022 (diff) | |
parent | 895238088417b292e35705e72182ff8cc3ab6f63 (diff) |
Merge #2151
2151: Resolve (and complete) trait calls like `Vec::default()` r=flodiebold a=flodiebold
Similar to rustc, we do this using the same code as the method call resolution, just without doing autoderef (and considering more potential candidates).
(Btw, we currently don't complete methods with `self` in path notation, even though they'd be legal to use, so maybe we should -- on the other hand, that will usually not be the most interesting completions...)
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 9 | ||||
-rw-r--r-- | crates/ra_hir/src/generics.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 36 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 19 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/path.rs | 82 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 141 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 173 |
7 files changed, 370 insertions, 93 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index ae6ef7606..c97ea18a2 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -1053,4 +1053,13 @@ impl AssocItem { | |||
1053 | AssocItem::TypeAlias(t) => t.module(db), | 1053 | AssocItem::TypeAlias(t) => t.module(db), |
1054 | } | 1054 | } |
1055 | } | 1055 | } |
1056 | |||
1057 | pub fn container(self, db: &impl DefDatabase) -> Container { | ||
1058 | match self { | ||
1059 | AssocItem::Function(f) => f.container(db), | ||
1060 | AssocItem::Const(c) => c.container(db), | ||
1061 | AssocItem::TypeAlias(t) => t.container(db), | ||
1062 | } | ||
1063 | .expect("AssocItem without container") | ||
1064 | } | ||
1056 | } | 1065 | } |
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs index 52e1fbf29..9c261eda9 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs | |||
@@ -77,9 +77,10 @@ impl GenericParams { | |||
77 | let parent = match def { | 77 | let parent = match def { |
78 | GenericDef::Function(it) => it.container(db).map(GenericDef::from), | 78 | GenericDef::Function(it) => it.container(db).map(GenericDef::from), |
79 | GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from), | 79 | GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from), |
80 | GenericDef::Const(it) => it.container(db).map(GenericDef::from), | ||
80 | GenericDef::EnumVariant(it) => Some(it.parent_enum(db).into()), | 81 | GenericDef::EnumVariant(it) => Some(it.parent_enum(db).into()), |
81 | GenericDef::Adt(_) | GenericDef::Trait(_) => None, | 82 | GenericDef::Adt(_) | GenericDef::Trait(_) => None, |
82 | GenericDef::ImplBlock(_) | GenericDef::Const(_) => None, | 83 | GenericDef::ImplBlock(_) => None, |
83 | }; | 84 | }; |
84 | let mut generics = GenericParams { | 85 | let mut generics = GenericParams { |
85 | def, | 86 | def, |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 0008cb232..a4ca59bba 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -27,9 +27,9 @@ use crate::{ | |||
27 | }, | 27 | }, |
28 | ids::LocationCtx, | 28 | ids::LocationCtx, |
29 | resolve::{ScopeDef, TypeNs, ValueNs}, | 29 | resolve::{ScopeDef, TypeNs, ValueNs}, |
30 | ty::method_resolution::implements_trait, | 30 | ty::method_resolution::{self, implements_trait}, |
31 | Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, MacroDef, Module, | 31 | AssocItem, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, |
32 | Name, Path, Resolver, Static, Struct, Ty, | 32 | MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty, |
33 | }; | 33 | }; |
34 | 34 | ||
35 | fn try_get_resolver_for_node( | 35 | fn try_get_resolver_for_node( |
@@ -327,16 +327,42 @@ impl SourceAnalyzer { | |||
327 | db: &impl HirDatabase, | 327 | db: &impl HirDatabase, |
328 | ty: Ty, | 328 | ty: Ty, |
329 | name: Option<&Name>, | 329 | name: Option<&Name>, |
330 | callback: impl FnMut(&Ty, Function) -> Option<T>, | 330 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, |
331 | ) -> Option<T> { | 331 | ) -> Option<T> { |
332 | // There should be no inference vars in types passed here | 332 | // There should be no inference vars in types passed here |
333 | // FIXME check that? | 333 | // FIXME check that? |
334 | // FIXME replace Unknown by bound vars here | ||
334 | let canonical = crate::ty::Canonical { value: ty, num_vars: 0 }; | 335 | let canonical = crate::ty::Canonical { value: ty, num_vars: 0 }; |
335 | crate::ty::method_resolution::iterate_method_candidates( | 336 | method_resolution::iterate_method_candidates( |
336 | &canonical, | 337 | &canonical, |
337 | db, | 338 | db, |
338 | &self.resolver, | 339 | &self.resolver, |
339 | name, | 340 | name, |
341 | method_resolution::LookupMode::MethodCall, | ||
342 | |ty, it| match it { | ||
343 | AssocItem::Function(f) => callback(ty, f), | ||
344 | _ => None, | ||
345 | }, | ||
346 | ) | ||
347 | } | ||
348 | |||
349 | pub fn iterate_path_candidates<T>( | ||
350 | &self, | ||
351 | db: &impl HirDatabase, | ||
352 | ty: Ty, | ||
353 | name: Option<&Name>, | ||
354 | callback: impl FnMut(&Ty, AssocItem) -> Option<T>, | ||
355 | ) -> Option<T> { | ||
356 | // There should be no inference vars in types passed here | ||
357 | // FIXME check that? | ||
358 | // FIXME replace Unknown by bound vars here | ||
359 | let canonical = crate::ty::Canonical { value: ty, num_vars: 0 }; | ||
360 | method_resolution::iterate_method_candidates( | ||
361 | &canonical, | ||
362 | db, | ||
363 | &self.resolver, | ||
364 | name, | ||
365 | method_resolution::LookupMode::Path, | ||
340 | callback, | 366 | callback, |
341 | ) | 367 | ) |
342 | } | 368 | } |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index d2bfcdc7d..d1a9d7411 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -385,13 +385,22 @@ impl SubstsBuilder { | |||
385 | self.param_count - self.vec.len() | 385 | self.param_count - self.vec.len() |
386 | } | 386 | } |
387 | 387 | ||
388 | pub fn fill_with_bound_vars(mut self, starting_from: u32) -> Self { | 388 | pub fn fill_with_bound_vars(self, starting_from: u32) -> Self { |
389 | self.vec.extend((starting_from..starting_from + self.remaining() as u32).map(Ty::Bound)); | 389 | self.fill((starting_from..).map(Ty::Bound)) |
390 | self | 390 | } |
391 | |||
392 | pub fn fill_with_params(self) -> Self { | ||
393 | let start = self.vec.len() as u32; | ||
394 | self.fill((start..).map(|idx| Ty::Param { idx, name: Name::missing() })) | ||
395 | } | ||
396 | |||
397 | pub fn fill_with_unknown(self) -> Self { | ||
398 | self.fill(iter::repeat(Ty::Unknown)) | ||
391 | } | 399 | } |
392 | 400 | ||
393 | pub fn fill_with_unknown(mut self) -> Self { | 401 | pub fn fill(mut self, filler: impl Iterator<Item = Ty>) -> Self { |
394 | self.vec.extend(iter::repeat(Ty::Unknown).take(self.remaining())); | 402 | self.vec.extend(filler.take(self.remaining())); |
403 | assert_eq!(self.remaining(), 0); | ||
395 | self | 404 | self |
396 | } | 405 | } |
397 | 406 | ||
diff --git a/crates/ra_hir/src/ty/infer/path.rs b/crates/ra_hir/src/ty/infer/path.rs index 77aa35ce1..59b7f7eb6 100644 --- a/crates/ra_hir/src/ty/infer/path.rs +++ b/crates/ra_hir/src/ty/infer/path.rs | |||
@@ -6,8 +6,8 @@ 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::{Substs, Ty, TypableDef, TypeWalk}, | 9 | ty::{method_resolution, Substs, Ty, TypableDef, TypeWalk}, |
10 | AssocItem, HasGenericParams, Namespace, Path, | 10 | AssocItem, Container, HasGenericParams, Name, Namespace, Path, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 13 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
@@ -39,7 +39,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
39 | let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty); | 39 | let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty); |
40 | self.resolve_ty_assoc_item( | 40 | self.resolve_ty_assoc_item( |
41 | ty, | 41 | ty, |
42 | path.segments.last().expect("path had at least one segment"), | 42 | &path.segments.last().expect("path had at least one segment").name, |
43 | id, | 43 | id, |
44 | )? | 44 | )? |
45 | } else { | 45 | } else { |
@@ -122,10 +122,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
122 | return None; | 122 | return None; |
123 | } | 123 | } |
124 | 124 | ||
125 | let ty = self.insert_type_vars(ty); | ||
126 | let ty = self.normalize_associated_types_in(ty); | ||
127 | |||
125 | let segment = | 128 | let segment = |
126 | remaining_segments.last().expect("there should be at least one segment here"); | 129 | remaining_segments.last().expect("there should be at least one segment here"); |
127 | 130 | ||
128 | self.resolve_ty_assoc_item(ty, segment, id) | 131 | self.resolve_ty_assoc_item(ty, &segment.name, id) |
129 | } | 132 | } |
130 | } | 133 | } |
131 | } | 134 | } |
@@ -162,7 +165,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
162 | }; | 165 | }; |
163 | let substs = Substs::build_for_def(self.db, item) | 166 | let substs = Substs::build_for_def(self.db, item) |
164 | .use_parent_substs(&trait_ref.substs) | 167 | .use_parent_substs(&trait_ref.substs) |
165 | .fill_with_unknown() | 168 | .fill_with_params() |
166 | .build(); | 169 | .build(); |
167 | 170 | ||
168 | self.write_assoc_resolution(id, item); | 171 | self.write_assoc_resolution(id, item); |
@@ -172,44 +175,51 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
172 | fn resolve_ty_assoc_item( | 175 | fn resolve_ty_assoc_item( |
173 | &mut self, | 176 | &mut self, |
174 | ty: Ty, | 177 | ty: Ty, |
175 | segment: &PathSegment, | 178 | name: &Name, |
176 | id: ExprOrPatId, | 179 | id: ExprOrPatId, |
177 | ) -> Option<(ValueNs, Option<Substs>)> { | 180 | ) -> Option<(ValueNs, Option<Substs>)> { |
178 | if let Ty::Unknown = ty { | 181 | if let Ty::Unknown = ty { |
179 | return None; | 182 | return None; |
180 | } | 183 | } |
181 | 184 | ||
182 | let krate = self.resolver.krate()?; | 185 | let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); |
183 | 186 | ||
184 | // Find impl | 187 | method_resolution::iterate_method_candidates( |
185 | // FIXME: consider trait candidates | 188 | &canonical_ty.value, |
186 | let item = ty.clone().iterate_impl_items(self.db, krate, |item| match item { | 189 | self.db, |
187 | AssocItem::Function(func) => { | 190 | &self.resolver.clone(), |
188 | if segment.name == func.name(self.db) { | 191 | Some(name), |
189 | Some(AssocItem::Function(func)) | 192 | method_resolution::LookupMode::Path, |
190 | } else { | 193 | move |_ty, item| { |
191 | None | 194 | let def = match item { |
192 | } | 195 | AssocItem::Function(f) => ValueNs::Function(f), |
193 | } | 196 | AssocItem::Const(c) => ValueNs::Const(c), |
194 | 197 | AssocItem::TypeAlias(_) => unreachable!(), | |
195 | AssocItem::Const(konst) => { | 198 | }; |
196 | if konst.name(self.db).map_or(false, |n| n == segment.name) { | 199 | let substs = match item.container(self.db) { |
197 | Some(AssocItem::Const(konst)) | 200 | Container::ImplBlock(_) => self.find_self_types(&def, ty.clone()), |
198 | } else { | 201 | Container::Trait(t) => { |
199 | None | 202 | // we're picking this method |
200 | } | 203 | let trait_substs = Substs::build_for_def(self.db, t) |
201 | } | 204 | .push(ty.clone()) |
202 | AssocItem::TypeAlias(_) => None, | 205 | .fill(std::iter::repeat_with(|| self.new_type_var())) |
203 | })?; | 206 | .build(); |
204 | let def = match item { | 207 | let substs = Substs::build_for_def(self.db, item) |
205 | AssocItem::Function(f) => ValueNs::Function(f), | 208 | .use_parent_substs(&trait_substs) |
206 | AssocItem::Const(c) => ValueNs::Const(c), | 209 | .fill_with_params() |
207 | AssocItem::TypeAlias(_) => unreachable!(), | 210 | .build(); |
208 | }; | 211 | self.obligations.push(super::Obligation::Trait(TraitRef { |
209 | let substs = self.find_self_types(&def, ty); | 212 | trait_: t, |
213 | substs: trait_substs, | ||
214 | })); | ||
215 | Some(substs) | ||
216 | } | ||
217 | }; | ||
210 | 218 | ||
211 | self.write_assoc_resolution(id, item); | 219 | self.write_assoc_resolution(id, item); |
212 | Some((def, substs)) | 220 | Some((def, substs)) |
221 | }, | ||
222 | ) | ||
213 | } | 223 | } |
214 | 224 | ||
215 | fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { | 225 | fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index eb69344f6..8c3d32d09 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -166,37 +166,78 @@ 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| match f |
170 | { | ||
171 | AssocItem::Function(f) => Some((ty.clone(), f)), | ||
172 | _ => None, | ||
173 | }) | ||
174 | } | ||
175 | |||
176 | /// Whether we're looking up a dotted method call (like `v.len()`) or a path | ||
177 | /// (like `Vec::new`). | ||
178 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
179 | pub enum LookupMode { | ||
180 | /// Looking up a method call like `v.len()`: We only consider candidates | ||
181 | /// that have a `self` parameter, and do autoderef. | ||
182 | MethodCall, | ||
183 | /// Looking up a path like `Vec::new` or `Vec::default`: We consider all | ||
184 | /// candidates including associated constants, but don't do autoderef. | ||
185 | Path, | ||
170 | } | 186 | } |
171 | 187 | ||
172 | // This would be nicer if it just returned an iterator, but that runs into | 188 | // This would be nicer if it just returned an iterator, but that runs into |
173 | // lifetime problems, because we need to borrow temp `CrateImplBlocks`. | 189 | // lifetime problems, because we need to borrow temp `CrateImplBlocks`. |
190 | // FIXME add a context type here? | ||
174 | pub(crate) fn iterate_method_candidates<T>( | 191 | pub(crate) fn iterate_method_candidates<T>( |
175 | ty: &Canonical<Ty>, | 192 | ty: &Canonical<Ty>, |
176 | db: &impl HirDatabase, | 193 | db: &impl HirDatabase, |
177 | resolver: &Resolver, | 194 | resolver: &Resolver, |
178 | name: Option<&Name>, | 195 | name: Option<&Name>, |
179 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | 196 | mode: LookupMode, |
197 | mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, | ||
180 | ) -> Option<T> { | 198 | ) -> Option<T> { |
181 | // For method calls, rust first does any number of autoderef, and then one | 199 | let krate = resolver.krate()?; |
182 | // autoref (i.e. when the method takes &self or &mut self). We just ignore | 200 | match mode { |
183 | // the autoref currently -- when we find a method matching the given name, | 201 | LookupMode::MethodCall => { |
184 | // we assume it fits. | 202 | // For method calls, rust first does any number of autoderef, and then one |
203 | // autoref (i.e. when the method takes &self or &mut self). We just ignore | ||
204 | // the autoref currently -- when we find a method matching the given name, | ||
205 | // we assume it fits. | ||
185 | 206 | ||
186 | // Also note that when we've got a receiver like &S, even if the method we | 207 | // Also note that when we've got a receiver like &S, even if the method we |
187 | // find in the end takes &self, we still do the autoderef step (just as | 208 | // find in the end takes &self, we still do the autoderef step (just as |
188 | // rustc does an autoderef and then autoref again). | 209 | // rustc does an autoderef and then autoref again). |
189 | 210 | ||
190 | let krate = resolver.krate()?; | 211 | for derefed_ty in autoderef::autoderef(db, resolver, ty.clone()) { |
191 | for derefed_ty in autoderef::autoderef(db, resolver, ty.clone()) { | 212 | if let Some(result) = |
192 | if let Some(result) = iterate_inherent_methods(&derefed_ty, db, name, krate, &mut callback) | 213 | iterate_inherent_methods(&derefed_ty, db, name, mode, krate, &mut callback) |
193 | { | 214 | { |
194 | return Some(result); | 215 | return Some(result); |
216 | } | ||
217 | if let Some(result) = iterate_trait_method_candidates( | ||
218 | &derefed_ty, | ||
219 | db, | ||
220 | resolver, | ||
221 | name, | ||
222 | mode, | ||
223 | &mut callback, | ||
224 | ) { | ||
225 | return Some(result); | ||
226 | } | ||
227 | } | ||
195 | } | 228 | } |
196 | if let Some(result) = | 229 | LookupMode::Path => { |
197 | iterate_trait_method_candidates(&derefed_ty, db, resolver, name, &mut callback) | 230 | // No autoderef for path lookups |
198 | { | 231 | if let Some(result) = |
199 | return Some(result); | 232 | iterate_inherent_methods(&ty, db, name, mode, krate, &mut callback) |
233 | { | ||
234 | return Some(result); | ||
235 | } | ||
236 | if let Some(result) = | ||
237 | iterate_trait_method_candidates(&ty, db, resolver, name, mode, &mut callback) | ||
238 | { | ||
239 | return Some(result); | ||
240 | } | ||
200 | } | 241 | } |
201 | } | 242 | } |
202 | None | 243 | None |
@@ -207,7 +248,8 @@ fn iterate_trait_method_candidates<T>( | |||
207 | db: &impl HirDatabase, | 248 | db: &impl HirDatabase, |
208 | resolver: &Resolver, | 249 | resolver: &Resolver, |
209 | name: Option<&Name>, | 250 | name: Option<&Name>, |
210 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | 251 | mode: LookupMode, |
252 | mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, | ||
211 | ) -> Option<T> { | 253 | ) -> Option<T> { |
212 | let krate = resolver.krate()?; | 254 | let krate = resolver.krate()?; |
213 | // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) | 255 | // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) |
@@ -231,22 +273,20 @@ fn iterate_trait_method_candidates<T>( | |||
231 | // trait, but if we find out it doesn't, we'll skip the rest of the | 273 | // trait, but if we find out it doesn't, we'll skip the rest of the |
232 | // iteration | 274 | // iteration |
233 | let mut known_implemented = inherently_implemented; | 275 | let mut known_implemented = inherently_implemented; |
234 | for item in data.items() { | 276 | for &item in data.items() { |
235 | if let AssocItem::Function(m) = *item { | 277 | if !is_valid_candidate(db, name, mode, item) { |
236 | let data = m.data(db); | 278 | continue; |
237 | if name.map_or(true, |name| data.name() == name) && data.has_self_param() { | 279 | } |
238 | if !known_implemented { | 280 | if !known_implemented { |
239 | let goal = generic_implements_goal(db, env.clone(), t, ty.clone()); | 281 | let goal = generic_implements_goal(db, env.clone(), t, ty.clone()); |
240 | if db.trait_solve(krate, goal).is_none() { | 282 | if db.trait_solve(krate, goal).is_none() { |
241 | continue 'traits; | 283 | continue 'traits; |
242 | } | ||
243 | } | ||
244 | known_implemented = true; | ||
245 | if let Some(result) = callback(&ty.value, m) { | ||
246 | return Some(result); | ||
247 | } | ||
248 | } | 284 | } |
249 | } | 285 | } |
286 | known_implemented = true; | ||
287 | if let Some(result) = callback(&ty.value, item) { | ||
288 | return Some(result); | ||
289 | } | ||
250 | } | 290 | } |
251 | } | 291 | } |
252 | None | 292 | None |
@@ -256,21 +296,20 @@ fn iterate_inherent_methods<T>( | |||
256 | ty: &Canonical<Ty>, | 296 | ty: &Canonical<Ty>, |
257 | db: &impl HirDatabase, | 297 | db: &impl HirDatabase, |
258 | name: Option<&Name>, | 298 | name: Option<&Name>, |
299 | mode: LookupMode, | ||
259 | krate: Crate, | 300 | krate: Crate, |
260 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | 301 | mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, |
261 | ) -> Option<T> { | 302 | ) -> Option<T> { |
262 | for krate in def_crates(db, krate, &ty.value)? { | 303 | for krate in def_crates(db, krate, &ty.value)? { |
263 | let impls = db.impls_in_crate(krate); | 304 | let impls = db.impls_in_crate(krate); |
264 | 305 | ||
265 | for impl_block in impls.lookup_impl_blocks(&ty.value) { | 306 | for impl_block in impls.lookup_impl_blocks(&ty.value) { |
266 | for item in impl_block.items(db) { | 307 | for item in impl_block.items(db) { |
267 | if let AssocItem::Function(f) = item { | 308 | if !is_valid_candidate(db, name, mode, item) { |
268 | let data = f.data(db); | 309 | continue; |
269 | if name.map_or(true, |name| data.name() == name) && data.has_self_param() { | 310 | } |
270 | if let Some(result) = callback(&ty.value, f) { | 311 | if let Some(result) = callback(&ty.value, item) { |
271 | return Some(result); | 312 | return Some(result); |
272 | } | ||
273 | } | ||
274 | } | 313 | } |
275 | } | 314 | } |
276 | } | 315 | } |
@@ -278,6 +317,26 @@ fn iterate_inherent_methods<T>( | |||
278 | None | 317 | None |
279 | } | 318 | } |
280 | 319 | ||
320 | fn is_valid_candidate( | ||
321 | db: &impl HirDatabase, | ||
322 | name: Option<&Name>, | ||
323 | mode: LookupMode, | ||
324 | item: AssocItem, | ||
325 | ) -> bool { | ||
326 | match item { | ||
327 | AssocItem::Function(m) => { | ||
328 | let data = m.data(db); | ||
329 | name.map_or(true, |name| data.name() == name) | ||
330 | && (data.has_self_param() || mode == LookupMode::Path) | ||
331 | } | ||
332 | AssocItem::Const(c) => { | ||
333 | name.map_or(true, |name| Some(name) == c.name(db).as_ref()) | ||
334 | && (mode == LookupMode::Path) | ||
335 | } | ||
336 | _ => false, | ||
337 | } | ||
338 | } | ||
339 | |||
281 | pub(crate) fn implements_trait( | 340 | pub(crate) fn implements_trait( |
282 | ty: &Canonical<Ty>, | 341 | ty: &Canonical<Ty>, |
283 | db: &impl HirDatabase, | 342 | db: &impl HirDatabase, |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index c12326643..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 | } |
@@ -2782,9 +2782,9 @@ fn test() { | |||
2782 | [97; 99) 's1': S | 2782 | [97; 99) 's1': S |
2783 | [105; 121) 'Defaul...efault': fn default<S>() -> Self | 2783 | [105; 121) 'Defaul...efault': fn default<S>() -> Self |
2784 | [105; 123) 'Defaul...ault()': S | 2784 | [105; 123) 'Defaul...ault()': S |
2785 | [133; 135) 's2': {unknown} | 2785 | [133; 135) 's2': S |
2786 | [138; 148) 'S::default': {unknown} | 2786 | [138; 148) 'S::default': fn default<S>() -> Self |
2787 | [138; 150) 'S::default()': {unknown} | 2787 | [138; 150) 'S::default()': S |
2788 | [160; 162) 's3': S | 2788 | [160; 162) 's3': S |
2789 | [165; 188) '<S as ...efault': fn default<S>() -> Self | 2789 | [165; 188) '<S as ...efault': fn default<S>() -> Self |
2790 | [165; 190) '<S as ...ault()': S | 2790 | [165; 190) '<S as ...ault()': S |
@@ -2793,6 +2793,153 @@ fn test() { | |||
2793 | } | 2793 | } |
2794 | 2794 | ||
2795 | #[test] | 2795 | #[test] |
2796 | fn infer_trait_assoc_method_generics_1() { | ||
2797 | assert_snapshot!( | ||
2798 | infer(r#" | ||
2799 | trait Trait<T> { | ||
2800 | fn make() -> T; | ||
2801 | } | ||
2802 | struct S; | ||
2803 | impl Trait<u32> for S {} | ||
2804 | struct G<T>; | ||
2805 | impl<T> Trait<T> for G<T> {} | ||
2806 | fn test() { | ||
2807 | let a = S::make(); | ||
2808 | let b = G::<u64>::make(); | ||
2809 | let c: f64 = G::make(); | ||
2810 | } | ||
2811 | "#), | ||
2812 | @r###" | ||
2813 | [127; 211) '{ ...e(); }': () | ||
2814 | [137; 138) 'a': u32 | ||
2815 | [141; 148) 'S::make': fn make<S, u32>() -> T | ||
2816 | [141; 150) 'S::make()': u32 | ||
2817 | [160; 161) 'b': u64 | ||
2818 | [164; 178) 'G::<u64>::make': fn make<G<u64>, u64>() -> T | ||
2819 | [164; 180) 'G::<u6...make()': u64 | ||
2820 | [190; 191) 'c': f64 | ||
2821 | [199; 206) 'G::make': fn make<G<f64>, f64>() -> T | ||
2822 | [199; 208) 'G::make()': f64 | ||
2823 | "### | ||
2824 | ); | ||
2825 | } | ||
2826 | |||
2827 | #[test] | ||
2828 | fn infer_trait_assoc_method_generics_2() { | ||
2829 | assert_snapshot!( | ||
2830 | infer(r#" | ||
2831 | trait Trait<T> { | ||
2832 | fn make<U>() -> (T, U); | ||
2833 | } | ||
2834 | struct S; | ||
2835 | impl Trait<u32> for S {} | ||
2836 | struct G<T>; | ||
2837 | impl<T> Trait<T> for G<T> {} | ||
2838 | fn test() { | ||
2839 | let a = S::make::<i64>(); | ||
2840 | let b: (_, i64) = S::make(); | ||
2841 | let c = G::<u32>::make::<i64>(); | ||
2842 | let d: (u32, _) = G::make::<i64>(); | ||
2843 | let e: (u32, i64) = G::make(); | ||
2844 | } | ||
2845 | "#), | ||
2846 | @r###" | ||
2847 | [135; 313) '{ ...e(); }': () | ||
2848 | [145; 146) 'a': (u32, i64) | ||
2849 | [149; 163) 'S::make::<i64>': fn make<S, u32, i64>() -> (T, U) | ||
2850 | [149; 165) 'S::mak...i64>()': (u32, i64) | ||
2851 | [175; 176) 'b': (u32, i64) | ||
2852 | [189; 196) 'S::make': fn make<S, u32, i64>() -> (T, U) | ||
2853 | [189; 198) 'S::make()': (u32, i64) | ||
2854 | [208; 209) 'c': (u32, i64) | ||
2855 | [212; 233) 'G::<u3...:<i64>': fn make<G<u32>, u32, i64>() -> (T, U) | ||
2856 | [212; 235) 'G::<u3...i64>()': (u32, i64) | ||
2857 | [245; 246) 'd': (u32, i64) | ||
2858 | [259; 273) 'G::make::<i64>': fn make<G<u32>, u32, i64>() -> (T, U) | ||
2859 | [259; 275) 'G::mak...i64>()': (u32, i64) | ||
2860 | [285; 286) 'e': (u32, i64) | ||
2861 | [301; 308) 'G::make': fn make<G<u32>, u32, i64>() -> (T, U) | ||
2862 | [301; 310) 'G::make()': (u32, i64) | ||
2863 | "### | ||
2864 | ); | ||
2865 | } | ||
2866 | |||
2867 | #[test] | ||
2868 | fn infer_trait_assoc_method_generics_3() { | ||
2869 | assert_snapshot!( | ||
2870 | infer(r#" | ||
2871 | trait Trait<T> { | ||
2872 | fn make() -> (Self, T); | ||
2873 | } | ||
2874 | struct S<T>; | ||
2875 | impl Trait<i64> for S<i32> {} | ||
2876 | fn test() { | ||
2877 | let a = S::make(); | ||
2878 | } | ||
2879 | "#), | ||
2880 | @r###" | ||
2881 | [101; 127) '{ ...e(); }': () | ||
2882 | [111; 112) 'a': (S<i32>, i64) | ||
2883 | [115; 122) 'S::make': fn make<S<i32>, i64>() -> (Self, T) | ||
2884 | [115; 124) 'S::make()': (S<i32>, i64) | ||
2885 | "### | ||
2886 | ); | ||
2887 | } | ||
2888 | |||
2889 | #[test] | ||
2890 | fn infer_trait_assoc_method_generics_4() { | ||
2891 | assert_snapshot!( | ||
2892 | infer(r#" | ||
2893 | trait Trait<T> { | ||
2894 | fn make() -> (Self, T); | ||
2895 | } | ||
2896 | struct S<T>; | ||
2897 | impl Trait<i64> for S<u64> {} | ||
2898 | impl Trait<i32> for S<u32> {} | ||
2899 | fn test() { | ||
2900 | let a: (S<u64>, _) = S::make(); | ||
2901 | let b: (_, i32) = S::make(); | ||
2902 | } | ||
2903 | "#), | ||
2904 | @r###" | ||
2905 | [131; 203) '{ ...e(); }': () | ||
2906 | [141; 142) 'a': (S<u64>, i64) | ||
2907 | [158; 165) 'S::make': fn make<S<u64>, i64>() -> (Self, T) | ||
2908 | [158; 167) 'S::make()': (S<u64>, i64) | ||
2909 | [177; 178) 'b': (S<u32>, i32) | ||
2910 | [191; 198) 'S::make': fn make<S<u32>, i32>() -> (Self, T) | ||
2911 | [191; 200) 'S::make()': (S<u32>, i32) | ||
2912 | "### | ||
2913 | ); | ||
2914 | } | ||
2915 | |||
2916 | #[test] | ||
2917 | fn infer_trait_assoc_method_generics_5() { | ||
2918 | assert_snapshot!( | ||
2919 | infer(r#" | ||
2920 | trait Trait<T> { | ||
2921 | fn make<U>() -> (Self, T, U); | ||
2922 | } | ||
2923 | struct S<T>; | ||
2924 | impl Trait<i64> for S<u64> {} | ||
2925 | fn test() { | ||
2926 | let a = <S as Trait<i64>>::make::<u8>(); | ||
2927 | let b: (S<u64>, _, _) = Trait::<i64>::make::<u8>(); | ||
2928 | } | ||
2929 | "#), | ||
2930 | @r###" | ||
2931 | [107; 211) '{ ...>(); }': () | ||
2932 | [117; 118) 'a': (S<u64>, i64, u8) | ||
2933 | [121; 150) '<S as ...::<u8>': fn make<S<u64>, i64, u8>() -> (Self, T, U) | ||
2934 | [121; 152) '<S as ...<u8>()': (S<u64>, i64, u8) | ||
2935 | [162; 163) 'b': (S<u64>, i64, u8) | ||
2936 | [182; 206) 'Trait:...::<u8>': fn make<S<u64>, i64, u8>() -> (Self, T, U) | ||
2937 | [182; 208) 'Trait:...<u8>()': (S<u64>, i64, u8) | ||
2938 | "### | ||
2939 | ); | ||
2940 | } | ||
2941 | |||
2942 | #[test] | ||
2796 | fn infer_from_bound_1() { | 2943 | fn infer_from_bound_1() { |
2797 | assert_snapshot!( | 2944 | assert_snapshot!( |
2798 | infer(r#" | 2945 | infer(r#" |
@@ -3303,6 +3450,22 @@ fn test() { S.foo()<|>; } | |||
3303 | assert_eq!(t, "u128"); | 3450 | assert_eq!(t, "u128"); |
3304 | } | 3451 | } |
3305 | 3452 | ||
3453 | #[ignore] | ||
3454 | #[test] | ||
3455 | fn method_resolution_by_value_before_autoref() { | ||
3456 | let t = type_at( | ||
3457 | r#" | ||
3458 | //- /main.rs | ||
3459 | trait Clone { fn clone(&self) -> Self; } | ||
3460 | struct S; | ||
3461 | impl Clone for S {} | ||
3462 | impl Clone for &S {} | ||
3463 | fn test() { (S.clone(), (&S).clone(), (&&S).clone())<|>; } | ||
3464 | "#, | ||
3465 | ); | ||
3466 | assert_eq!(t, "(S, S, &S)"); | ||
3467 | } | ||
3468 | |||
3306 | #[test] | 3469 | #[test] |
3307 | fn method_resolution_trait_before_autoderef() { | 3470 | fn method_resolution_trait_before_autoderef() { |
3308 | let t = type_at( | 3471 | let t = type_at( |