@@ -322,6 +322,68 @@ impl SourceAnalyzer {
322322 }
323323 }
324324
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+
325387 pub ( crate ) fn resolve_expr_as_callable (
326388 & self ,
327389 db : & dyn HirDatabase ,
@@ -1247,6 +1309,18 @@ impl SourceAnalyzer {
12471309 Some ( ( trait_id, fn_id) )
12481310 }
12491311
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+
12501324 fn ty_of_expr ( & self , db : & dyn HirDatabase , expr : & ast:: Expr ) -> Option < & Ty > {
12511325 self . infer . as_ref ( ) ?. type_of_expr_or_pat ( self . expr_id ( db, expr) ?)
12521326 }
0 commit comments