@@ -5,10 +5,14 @@ use crate::{
55 navigation_target:: { self , ToNav } ,
66 FilePosition , NavigationTarget , RangeInfo , TryToNav , UpmappingResult ,
77} ;
8- use hir:: { AsAssocItem , AssocItem , FileRange , InFile , MacroFileIdExt , ModuleDef , Semantics } ;
8+ use hir:: {
9+ sym, AsAssocItem , AssocItem , CallableKind , FileRange , HasCrate , InFile , MacroFileIdExt ,
10+ ModuleDef , Semantics ,
11+ } ;
912use ide_db:: {
1013 base_db:: { AnchoredPath , FileLoader , SourceDatabase } ,
1114 defs:: { Definition , IdentClass } ,
15+ famous_defs:: FamousDefs ,
1216 helpers:: pick_best_token,
1317 RootDatabase , SymbolKind ,
1418} ;
@@ -129,15 +133,65 @@ pub(crate) fn goto_definition(
129133 Some ( RangeInfo :: new ( original_token. text_range ( ) , navs) )
130134}
131135
132- // If the token is into(), try_into(), parse(), search the definition of From, TryFrom, FromStr .
136+ // If the token is into(), try_into(), search the definition of From, TryFrom.
133137fn find_definition_for_known_blanket_dual_impls (
134138 sema : & Semantics < ' _ , RootDatabase > ,
135139 original_token : & SyntaxToken ,
136140) -> Option < Vec < NavigationTarget > > {
137141 let method_call = ast:: MethodCallExpr :: cast ( original_token. parent ( ) ?. parent ( ) ?) ?;
138- let target_method = sema. resolve_known_blanket_dual_impls ( & method_call) ?;
142+ let callable = sema. resolve_method_call_as_callable ( & method_call) ?;
143+ let CallableKind :: Function ( f) = callable. kind ( ) else { return None } ;
144+ let assoc = f. as_assoc_item ( sema. db ) ?;
145+
146+ let return_type = callable. return_type ( ) ;
147+ let fd = FamousDefs ( sema, return_type. krate ( sema. db ) ) ;
148+
149+ let t = match assoc. container ( sema. db ) {
150+ hir:: AssocItemContainer :: Trait ( t) => t,
151+ hir:: AssocItemContainer :: Impl ( impl_)
152+ if impl_. self_ty ( sema. db ) . is_str ( ) && f. name ( sema. db ) == sym:: parse =>
153+ {
154+ let t = fd. core_convert_FromStr ( ) ?;
155+ let t_f = t. function ( sema. db , & sym:: from_str) ?;
156+ return sema
157+ . resolve_trait_impl_method (
158+ return_type. clone ( ) ,
159+ t,
160+ t_f,
161+ [ return_type. type_arguments ( ) . next ( ) ?] ,
162+ )
163+ . map ( |f| def_to_nav ( sema. db , f. into ( ) ) ) ;
164+ }
165+ hir:: AssocItemContainer :: Impl ( _) => return None ,
166+ } ;
139167
140- let def = Definition :: from ( target_method) ;
168+ let fn_name = f. name ( sema. db ) ;
169+ let f = if fn_name == sym:: into && fd. core_convert_Into ( ) == Some ( t) {
170+ let dual = fd. core_convert_From ( ) ?;
171+ let dual_f = dual. function ( sema. db , & sym:: from) ?;
172+ sema. resolve_trait_impl_method (
173+ return_type. clone ( ) ,
174+ dual,
175+ dual_f,
176+ [ return_type, callable. receiver_param ( sema. db ) ?. 1 ] ,
177+ ) ?
178+ } else if fn_name == sym:: try_into && fd. core_convert_TryInto ( ) == Some ( t) {
179+ let dual = fd. core_convert_TryFrom ( ) ?;
180+ let dual_f = dual. function ( sema. db , & sym:: try_from) ?;
181+ sema. resolve_trait_impl_method (
182+ return_type. clone ( ) ,
183+ dual,
184+ dual_f,
185+ // Extract the `T` from `Result<T, ..>`
186+ [ return_type. type_arguments ( ) . next ( ) ?, callable. receiver_param ( sema. db ) ?. 1 ] ,
187+ ) ?
188+ } else {
189+ return None ;
190+ } ;
191+ // Assert that we got a trait impl function, if we are back in a trait definition we didn't
192+ // succeed
193+ let _t = f. as_assoc_item ( sema. db ) ?. implemented_trait ( sema. db ) ?;
194+ let def = Definition :: from ( f) ;
141195 Some ( def_to_nav ( sema. db , def) )
142196}
143197
@@ -3168,16 +3222,13 @@ fn f() {
31683222 r#"
31693223//- minicore: from, str
31703224struct A;
3171-
31723225impl FromStr for A {
31733226 type Error = String;
3174-
31753227 fn from_str(value: &str) -> Result<Self, Self::Error> {
31763228 //^^^^^^^^
31773229 Ok(A)
31783230 }
31793231}
3180-
31813232fn f() {
31823233 let a: Result<A, _> = "aaaaaa".parse$0();
31833234}
0 commit comments