@@ -322,6 +322,68 @@ impl SourceAnalyzer {
322
322
}
323
323
}
324
324
325
+ // If the method is into(), try_into(), parse(), resolve it to from, try_from, from_str.
326
+ pub ( crate ) fn resolve_known_blanket_dual_impls (
327
+ & self ,
328
+ db : & dyn HirDatabase ,
329
+ call : & ast:: MethodCallExpr ,
330
+ ) -> Option < Function > {
331
+ // e.g. if the method call is let b = a.into(),
332
+ // - receiver_type is A (type of a)
333
+ // - return_type is B (type of b)
334
+ // We will find the definition of B::from(a: A).
335
+ let callable = self . resolve_method_call_as_callable ( db, call) ?;
336
+ let ( _, receiver_type) = callable. receiver_param ( db) ?;
337
+ let return_type = callable. return_type ( ) ;
338
+ let ( search_method, substs) = match call. name_ref ( ) ?. text ( ) . as_str ( ) {
339
+ "into" => {
340
+ let trait_ =
341
+ self . resolver . resolve_known_trait ( db. upcast ( ) , & path ! [ core:: convert:: From ] ) ?;
342
+ (
343
+ self . trait_fn ( db, trait_, "from" ) ?,
344
+ hir_ty:: TyBuilder :: subst_for_def ( db, trait_, None )
345
+ . push ( return_type. ty )
346
+ . push ( receiver_type. ty )
347
+ . build ( ) ,
348
+ )
349
+ }
350
+ "try_into" => {
351
+ let trait_ = self
352
+ . resolver
353
+ . resolve_known_trait ( db. upcast ( ) , & path ! [ core:: convert:: TryFrom ] ) ?;
354
+ (
355
+ self . trait_fn ( db, trait_, "try_from" ) ?,
356
+ hir_ty:: TyBuilder :: subst_for_def ( db, trait_, None )
357
+ // If the method is try_into() or parse(), return_type is Result<T, Error>.
358
+ // Get T from type arguments of Result<T, Error>.
359
+ . push ( return_type. type_arguments ( ) . next ( ) ?. ty )
360
+ . push ( receiver_type. ty )
361
+ . build ( ) ,
362
+ )
363
+ }
364
+ "parse" => {
365
+ let trait_ =
366
+ self . resolver . resolve_known_trait ( db. upcast ( ) , & path ! [ core:: str :: FromStr ] ) ?;
367
+ (
368
+ self . trait_fn ( db, trait_, "from_str" ) ?,
369
+ hir_ty:: TyBuilder :: subst_for_def ( db, trait_, None )
370
+ . push ( return_type. type_arguments ( ) . next ( ) ?. ty )
371
+ . build ( ) ,
372
+ )
373
+ }
374
+ _ => return None ,
375
+ } ;
376
+
377
+ let found_method = self . resolve_impl_method_or_trait_def ( db, search_method, substs) ;
378
+ // If found_method == search_method, the method in trait itself is resolved.
379
+ // It means the blanket dual impl is not found.
380
+ if found_method == search_method {
381
+ None
382
+ } else {
383
+ Some ( found_method. into ( ) )
384
+ }
385
+ }
386
+
325
387
pub ( crate ) fn resolve_expr_as_callable (
326
388
& self ,
327
389
db : & dyn HirDatabase ,
@@ -1247,6 +1309,18 @@ impl SourceAnalyzer {
1247
1309
Some ( ( trait_id, fn_id) )
1248
1310
}
1249
1311
1312
+ fn trait_fn (
1313
+ & self ,
1314
+ db : & dyn HirDatabase ,
1315
+ trait_id : TraitId ,
1316
+ method_name : & str ,
1317
+ ) -> Option < FunctionId > {
1318
+ db. trait_data ( trait_id) . items . iter ( ) . find_map ( |( item_name, item) | match item {
1319
+ AssocItemId :: FunctionId ( t) if item_name. as_str ( ) == method_name => Some ( * t) ,
1320
+ _ => None ,
1321
+ } )
1322
+ }
1323
+
1250
1324
fn ty_of_expr ( & self , db : & dyn HirDatabase , expr : & ast:: Expr ) -> Option < & Ty > {
1251
1325
self . infer . as_ref ( ) ?. type_of_expr_or_pat ( self . expr_id ( db, expr) ?)
1252
1326
}
0 commit comments