@@ -5,10 +5,14 @@ use crate::{
5
5
navigation_target:: { self , ToNav } ,
6
6
FilePosition , NavigationTarget , RangeInfo , TryToNav , UpmappingResult ,
7
7
} ;
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
+ } ;
9
12
use ide_db:: {
10
13
base_db:: { AnchoredPath , FileLoader , SourceDatabase } ,
11
14
defs:: { Definition , IdentClass } ,
15
+ famous_defs:: FamousDefs ,
12
16
helpers:: pick_best_token,
13
17
RootDatabase , SymbolKind ,
14
18
} ;
@@ -129,15 +133,65 @@ pub(crate) fn goto_definition(
129
133
Some ( RangeInfo :: new ( original_token. text_range ( ) , navs) )
130
134
}
131
135
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.
133
137
fn find_definition_for_known_blanket_dual_impls (
134
138
sema : & Semantics < ' _ , RootDatabase > ,
135
139
original_token : & SyntaxToken ,
136
140
) -> Option < Vec < NavigationTarget > > {
137
141
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
+ } ;
139
167
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) ;
141
195
Some ( def_to_nav ( sema. db , def) )
142
196
}
143
197
@@ -3168,16 +3222,13 @@ fn f() {
3168
3222
r#"
3169
3223
//- minicore: from, str
3170
3224
struct A;
3171
-
3172
3225
impl FromStr for A {
3173
3226
type Error = String;
3174
-
3175
3227
fn from_str(value: &str) -> Result<Self, Self::Error> {
3176
3228
//^^^^^^^^
3177
3229
Ok(A)
3178
3230
}
3179
3231
}
3180
-
3181
3232
fn f() {
3182
3233
let a: Result<A, _> = "aaaaaa".parse$0();
3183
3234
}
0 commit comments