diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/hir_ty/src/infer.rs | 5 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/traits.rs | 37 | ||||
-rw-r--r-- | crates/ide/src/goto_implementation.rs | 46 |
3 files changed, 86 insertions, 2 deletions
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs index db3c937ff..edb65622f 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs | |||
@@ -580,7 +580,10 @@ impl<'a> InferenceContext<'a> { | |||
580 | fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> { | 580 | fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> { |
581 | let path = path![core::ops::Try]; | 581 | let path = path![core::ops::Try]; |
582 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; | 582 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; |
583 | self.db.trait_data(trait_).associated_type_by_name(&name![Ok]) | 583 | let trait_data = self.db.trait_data(trait_); |
584 | trait_data | ||
585 | .associated_type_by_name(&name![Ok]) | ||
586 | .or_else(|| trait_data.associated_type_by_name(&name![Output])) | ||
584 | } | 587 | } |
585 | 588 | ||
586 | fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> { | 589 | fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> { |
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index eea98fd4f..6cd8786ea 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs | |||
@@ -161,6 +161,43 @@ mod result { | |||
161 | } | 161 | } |
162 | 162 | ||
163 | #[test] | 163 | #[test] |
164 | fn infer_tryv2() { | ||
165 | check_types( | ||
166 | r#" | ||
167 | //- /main.rs crate:main deps:core | ||
168 | fn test() { | ||
169 | let r: Result<i32, u64> = Result::Ok(1); | ||
170 | let v = r?; | ||
171 | v; | ||
172 | } //^ i32 | ||
173 | |||
174 | //- /core.rs crate:core | ||
175 | #[prelude_import] use ops::*; | ||
176 | mod ops { | ||
177 | trait Try { | ||
178 | type Output; | ||
179 | type Residual; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | #[prelude_import] use result::*; | ||
184 | mod result { | ||
185 | enum Infallible {} | ||
186 | enum Result<O, E> { | ||
187 | Ok(O), | ||
188 | Err(E) | ||
189 | } | ||
190 | |||
191 | impl<O, E> crate::ops::Try for Result<O, E> { | ||
192 | type Output = O; | ||
193 | type Error = Result<Infallible, E>; | ||
194 | } | ||
195 | } | ||
196 | "#, | ||
197 | ); | ||
198 | } | ||
199 | |||
200 | #[test] | ||
164 | fn infer_for_loop() { | 201 | fn infer_for_loop() { |
165 | check_types( | 202 | check_types( |
166 | r#" | 203 | r#" |
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs index 05130a237..5a8d3c3f9 100644 --- a/crates/ide/src/goto_implementation.rs +++ b/crates/ide/src/goto_implementation.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use hir::{Impl, Semantics}; | 1 | use hir::{AsAssocItem, Impl, Semantics}; |
2 | use ide_db::{ | 2 | use ide_db::{ |
3 | defs::{Definition, NameClass, NameRefClass}, | 3 | defs::{Definition, NameClass, NameRefClass}, |
4 | RootDatabase, | 4 | RootDatabase, |
@@ -36,6 +36,7 @@ pub(crate) fn goto_implementation( | |||
36 | } | 36 | } |
37 | ast::NameLike::Lifetime(_) => None, | 37 | ast::NameLike::Lifetime(_) => None, |
38 | }?; | 38 | }?; |
39 | |||
39 | let def = match def { | 40 | let def = match def { |
40 | Definition::ModuleDef(def) => def, | 41 | Definition::ModuleDef(def) => def, |
41 | _ => return None, | 42 | _ => return None, |
@@ -48,6 +49,12 @@ pub(crate) fn goto_implementation( | |||
48 | let module = sema.to_module_def(position.file_id)?; | 49 | let module = sema.to_module_def(position.file_id)?; |
49 | impls_for_ty(&sema, builtin.ty(sema.db, module)) | 50 | impls_for_ty(&sema, builtin.ty(sema.db, module)) |
50 | } | 51 | } |
52 | hir::ModuleDef::Function(f) => { | ||
53 | let assoc = f.as_assoc_item(sema.db)?; | ||
54 | let name = assoc.name(sema.db)?; | ||
55 | let trait_ = assoc.containing_trait(sema.db)?; | ||
56 | impls_for_trait_fn(&sema, trait_, name) | ||
57 | } | ||
51 | _ => return None, | 58 | _ => return None, |
52 | }; | 59 | }; |
53 | Some(RangeInfo { range: node.syntax().text_range(), info: navs }) | 60 | Some(RangeInfo { range: node.syntax().text_range(), info: navs }) |
@@ -64,6 +71,23 @@ fn impls_for_trait(sema: &Semantics<RootDatabase>, trait_: hir::Trait) -> Vec<Na | |||
64 | .collect() | 71 | .collect() |
65 | } | 72 | } |
66 | 73 | ||
74 | fn impls_for_trait_fn( | ||
75 | sema: &Semantics<RootDatabase>, | ||
76 | trait_: hir::Trait, | ||
77 | fun_name: hir::Name, | ||
78 | ) -> Vec<NavigationTarget> { | ||
79 | Impl::all_for_trait(sema.db, trait_) | ||
80 | .into_iter() | ||
81 | .filter_map(|imp| { | ||
82 | let item = imp.items(sema.db).iter().find_map(|itm| { | ||
83 | let itm_name = itm.name(sema.db)?; | ||
84 | (itm_name == fun_name).then(|| itm.clone()) | ||
85 | })?; | ||
86 | item.try_to_nav(sema.db) | ||
87 | }) | ||
88 | .collect() | ||
89 | } | ||
90 | |||
67 | #[cfg(test)] | 91 | #[cfg(test)] |
68 | mod tests { | 92 | mod tests { |
69 | use ide_db::base_db::FileRange; | 93 | use ide_db::base_db::FileRange; |
@@ -262,4 +286,24 @@ impl bool {} | |||
262 | "#, | 286 | "#, |
263 | ); | 287 | ); |
264 | } | 288 | } |
289 | |||
290 | #[test] | ||
291 | fn goto_implementation_trait_functions() { | ||
292 | check( | ||
293 | r#" | ||
294 | trait Tr { | ||
295 | fn f$0(); | ||
296 | } | ||
297 | |||
298 | struct S; | ||
299 | |||
300 | impl Tr for S { | ||
301 | fn f() { | ||
302 | //^ | ||
303 | println!("Hello, world!"); | ||
304 | } | ||
305 | } | ||
306 | "#, | ||
307 | ); | ||
308 | } | ||
265 | } | 309 | } |