@@ -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,45 @@ 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) ?;
139-
140- let def = Definition :: from ( target_method) ;
142+ let callable = sema. resolve_method_call_as_callable ( & method_call) ?;
143+ let CallableKind :: Function ( f) = callable. kind ( ) else { return None } ;
144+ let t = f. as_assoc_item ( sema. db ) ?. container_trait ( sema. db ) ?;
145+
146+ let return_type = callable. return_type ( ) ;
147+ let fd = FamousDefs ( sema, return_type. krate ( sema. db ) ) ;
148+ let fn_name = f. name ( sema. db ) ;
149+ let f = if fn_name == sym:: into && fd. core_convert_Into ( ) == Some ( t) {
150+ let dual = fd. core_convert_From ( ) ?;
151+ let dual_f = dual. function ( sema. db , & sym:: from) ?;
152+ sema. resolve_impl_method (
153+ return_type. clone ( ) ,
154+ dual,
155+ dual_f,
156+ [ return_type, callable. receiver_param ( sema. db ) ?. 1 ] ,
157+ ) ?
158+ } else if fn_name == sym:: try_into && fd. core_convert_TryInto ( ) == Some ( t) {
159+ let dual = fd. core_convert_TryFrom ( ) ?;
160+ let dual_f = dual. function ( sema. db , & sym:: try_from) ?;
161+ sema. resolve_impl_method (
162+ return_type. clone ( ) ,
163+ dual,
164+ dual_f,
165+ // Extract the `T` from `Result<T, ..>`
166+ [ return_type. type_arguments ( ) . next ( ) ?, callable. receiver_param ( sema. db ) ?. 1 ] ,
167+ ) ?
168+ } else {
169+ return None ;
170+ } ;
171+ // Assert that we got a trait impl function, if we are back in a trait definition we didn't
172+ // succeed
173+ let _t = f. as_assoc_item ( sema. db ) ?. implemented_trait ( sema. db ) ?;
174+ let def = Definition :: from ( f) ;
141175 Some ( def_to_nav ( sema. db , def) )
142176}
143177
@@ -3157,29 +3191,6 @@ impl TryInto<B> for A {
31573191fn f() {
31583192 let a = A;
31593193 let b: Result<B, _> = a.try_into$0();
3160- }
3161- "# ,
3162- ) ;
3163- }
3164-
3165- #[ test]
3166- fn parse_call_to_from_str_definition ( ) {
3167- check (
3168- r#"
3169- //- minicore: from, str
3170- struct A;
3171-
3172- impl FromStr for A {
3173- type Error = String;
3174-
3175- fn from_str(value: &str) -> Result<Self, Self::Error> {
3176- //^^^^^^^^
3177- Ok(A)
3178- }
3179- }
3180-
3181- fn f() {
3182- let a: Result<A, _> = "aaaaaa".parse$0();
31833194}
31843195 "# ,
31853196 ) ;
0 commit comments