aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-11-01 19:03:05 +0000
committerGitHub <[email protected]>2019-11-01 19:03:05 +0000
commit9db97820f4c1c38110175f4efda2702356a4199a (patch)
treef560ab731b9da35902d3da720e19731b51ab62df /crates
parented5212e1ac71e959d802a9a7ad28d06c8b18e022 (diff)
parent895238088417b292e35705e72182ff8cc3ab6f63 (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')
-rw-r--r--crates/ra_hir/src/code_model.rs9
-rw-r--r--crates/ra_hir/src/generics.rs3
-rw-r--r--crates/ra_hir/src/source_binder.rs36
-rw-r--r--crates/ra_hir/src/ty.rs19
-rw-r--r--crates/ra_hir/src/ty/infer/path.rs82
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs141
-rw-r--r--crates/ra_hir/src/ty/tests.rs173
-rw-r--r--crates/ra_ide_api/src/completion/complete_path.rs142
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs55
9 files changed, 560 insertions, 100 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
35fn try_get_resolver_for_node( 35fn 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};
6use crate::{ 6use 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
13impl<'a, D: HirDatabase> InferenceContext<'a, D> { 13impl<'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)]
179pub 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?
174pub(crate) fn iterate_method_candidates<T>( 191pub(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
320fn 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
281pub(crate) fn implements_trait( 340pub(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]
2796fn infer_trait_assoc_method_generics_1() {
2797 assert_snapshot!(
2798 infer(r#"
2799trait Trait<T> {
2800 fn make() -> T;
2801}
2802struct S;
2803impl Trait<u32> for S {}
2804struct G<T>;
2805impl<T> Trait<T> for G<T> {}
2806fn 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]
2828fn infer_trait_assoc_method_generics_2() {
2829 assert_snapshot!(
2830 infer(r#"
2831trait Trait<T> {
2832 fn make<U>() -> (T, U);
2833}
2834struct S;
2835impl Trait<u32> for S {}
2836struct G<T>;
2837impl<T> Trait<T> for G<T> {}
2838fn 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]
2868fn infer_trait_assoc_method_generics_3() {
2869 assert_snapshot!(
2870 infer(r#"
2871trait Trait<T> {
2872 fn make() -> (Self, T);
2873}
2874struct S<T>;
2875impl Trait<i64> for S<i32> {}
2876fn 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]
2890fn infer_trait_assoc_method_generics_4() {
2891 assert_snapshot!(
2892 infer(r#"
2893trait Trait<T> {
2894 fn make() -> (Self, T);
2895}
2896struct S<T>;
2897impl Trait<i64> for S<u64> {}
2898impl Trait<i32> for S<u32> {}
2899fn 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]
2917fn infer_trait_assoc_method_generics_5() {
2918 assert_snapshot!(
2919 infer(r#"
2920trait Trait<T> {
2921 fn make<U>() -> (Self, T, U);
2922}
2923struct S<T>;
2924impl Trait<i64> for S<u64> {}
2925fn 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]
2796fn infer_from_bound_1() { 2943fn 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]
3455fn method_resolution_by_value_before_autoref() {
3456 let t = type_at(
3457 r#"
3458//- /main.rs
3459trait Clone { fn clone(&self) -> Self; }
3460struct S;
3461impl Clone for S {}
3462impl Clone for &S {}
3463fn test() { (S.clone(), (&S).clone(), (&&S).clone())<|>; }
3464"#,
3465 );
3466 assert_eq!(t, "(S, S, &S)");
3467}
3468
3306#[test] 3469#[test]
3307fn method_resolution_trait_before_autoderef() { 3470fn method_resolution_trait_before_autoderef() {
3308 let t = type_at( 3471 let t = type_at(
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs
index a58fdc036..9ac9768af 100644
--- a/crates/ra_ide_api/src/completion/complete_path.rs
+++ b/crates/ra_ide_api/src/completion/complete_path.rs
@@ -50,23 +50,46 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
50 hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db), 50 hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db),
51 _ => unreachable!(), 51 _ => unreachable!(),
52 }; 52 };
53 ctx.analyzer.iterate_path_candidates(ctx.db, ty.clone(), None, |_ty, item| {
54 match item {
55 hir::AssocItem::Function(func) => {
56 let data = func.data(ctx.db);
57 if !data.has_self_param() {
58 acc.add_function(ctx, func);
59 }
60 }
61 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
62 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
63 }
64 None::<()>
65 });
66 // Iterate assoc types separately
67 // FIXME: complete T::AssocType
53 let krate = ctx.module.map(|m| m.krate()); 68 let krate = ctx.module.map(|m| m.krate());
54 if let Some(krate) = krate { 69 if let Some(krate) = krate {
55 ty.iterate_impl_items(ctx.db, krate, |item| { 70 ty.iterate_impl_items(ctx.db, krate, |item| {
56 match item { 71 match item {
57 hir::AssocItem::Function(func) => { 72 hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => {}
58 let data = func.data(ctx.db);
59 if !data.has_self_param() {
60 acc.add_function(ctx, func);
61 }
62 }
63 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
64 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), 73 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
65 } 74 }
66 None::<()> 75 None::<()>
67 }); 76 });
68 } 77 }
69 } 78 }
79 hir::ModuleDef::Trait(t) => {
80 for item in t.items(ctx.db) {
81 match item {
82 hir::AssocItem::Function(func) => {
83 let data = func.data(ctx.db);
84 if !data.has_self_param() {
85 acc.add_function(ctx, func);
86 }
87 }
88 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
89 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
90 }
91 }
92 }
70 _ => {} 93 _ => {}
71 }; 94 };
72} 95}
@@ -559,6 +582,111 @@ mod tests {
559 } 582 }
560 583
561 #[test] 584 #[test]
585 fn completes_trait_associated_method_1() {
586 assert_debug_snapshot!(
587 do_reference_completion(
588 "
589 //- /lib.rs
590 trait Trait {
591 /// A trait method
592 fn m();
593 }
594
595 fn foo() { let _ = Trait::<|> }
596 "
597 ),
598 @r###"
599 [
600 CompletionItem {
601 label: "m()",
602 source_range: [73; 73),
603 delete: [73; 73),
604 insert: "m()$0",
605 kind: Function,
606 lookup: "m",
607 detail: "fn m()",
608 documentation: Documentation(
609 "A trait method",
610 ),
611 },
612 ]
613 "###
614 );
615 }
616
617 #[test]
618 fn completes_trait_associated_method_2() {
619 assert_debug_snapshot!(
620 do_reference_completion(
621 "
622 //- /lib.rs
623 trait Trait {
624 /// A trait method
625 fn m();
626 }
627
628 struct S;
629 impl Trait for S {}
630
631 fn foo() { let _ = S::<|> }
632 "
633 ),
634 @r###"
635 [
636 CompletionItem {
637 label: "m()",
638 source_range: [99; 99),
639 delete: [99; 99),
640 insert: "m()$0",
641 kind: Function,
642 lookup: "m",
643 detail: "fn m()",
644 documentation: Documentation(
645 "A trait method",
646 ),
647 },
648 ]
649 "###
650 );
651 }
652
653 #[test]
654 fn completes_trait_associated_method_3() {
655 assert_debug_snapshot!(
656 do_reference_completion(
657 "
658 //- /lib.rs
659 trait Trait {
660 /// A trait method
661 fn m();
662 }
663
664 struct S;
665 impl Trait for S {}
666
667 fn foo() { let _ = <S as Trait>::<|> }
668 "
669 ),
670 @r###"
671 [
672 CompletionItem {
673 label: "m()",
674 source_range: [110; 110),
675 delete: [110; 110),
676 insert: "m()$0",
677 kind: Function,
678 lookup: "m",
679 detail: "fn m()",
680 documentation: Documentation(
681 "A trait method",
682 ),
683 },
684 ]
685 "###
686 );
687 }
688
689 #[test]
562 fn completes_type_alias() { 690 fn completes_type_alias() {
563 assert_debug_snapshot!( 691 assert_debug_snapshot!(
564 do_reference_completion( 692 do_reference_completion(
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index 323faab33..c1ce54bea 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -390,6 +390,61 @@ mod tests {
390 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)", 390 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)",
391 ); 391 );
392 } 392 }
393
394 #[test]
395 fn goto_definition_works_for_ufcs_inherent_methods() {
396 check_goto(
397 "
398 //- /lib.rs
399 struct Foo;
400 impl Foo {
401 fn frobnicate() { }
402 }
403
404 fn bar(foo: &Foo) {
405 Foo::frobnicate<|>();
406 }
407 ",
408 "frobnicate FN_DEF FileId(1) [27; 47) [30; 40)",
409 );
410 }
411
412 #[test]
413 fn goto_definition_works_for_ufcs_trait_methods_through_traits() {
414 check_goto(
415 "
416 //- /lib.rs
417 trait Foo {
418 fn frobnicate();
419 }
420
421 fn bar() {
422 Foo::frobnicate<|>();
423 }
424 ",
425 "frobnicate FN_DEF FileId(1) [16; 32) [19; 29)",
426 );
427 }
428
429 #[test]
430 fn goto_definition_works_for_ufcs_trait_methods_through_self() {
431 check_goto(
432 "
433 //- /lib.rs
434 struct Foo;
435 trait Trait {
436 fn frobnicate();
437 }
438 impl Trait for Foo {}
439
440 fn bar() {
441 Foo::frobnicate<|>();
442 }
443 ",
444 "frobnicate FN_DEF FileId(1) [30; 46) [33; 43)",
445 );
446 }
447
393 #[test] 448 #[test]
394 fn goto_definition_on_self() { 449 fn goto_definition_on_self() {
395 check_goto( 450 check_goto(