@@ -452,17 +452,134 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
452452 let mut infer_subdiags = Vec :: new ( ) ;
453453 let mut multi_suggestions = Vec :: new ( ) ;
454454 match kind {
455- InferSourceKind :: LetBinding { insert_span, pattern_name, ty, def_id } => {
456- infer_subdiags. push ( SourceKindSubdiag :: LetLike {
457- span : insert_span,
458- name : pattern_name. map ( |name| name. to_string ( ) ) . unwrap_or_else ( String :: new) ,
459- x_kind : arg_data. where_x_is_kind ( ty) ,
460- prefix_kind : arg_data. kind . clone ( ) ,
461- prefix : arg_data. kind . try_get_prefix ( ) . unwrap_or_default ( ) ,
462- arg_name : arg_data. name ,
463- kind : if pattern_name. is_some ( ) { "with_pattern" } else { "other" } ,
464- type_name : ty_to_string ( self , ty, def_id) ,
465- } ) ;
455+ InferSourceKind :: LetBinding { insert_span, pattern_name, ty, def_id, hir_id } => {
456+ let mut paths = vec ! [ ] ;
457+ let param_env = ty:: ParamEnv :: reveal_all ( ) ;
458+ if let Some ( def_id) = def_id
459+ && let name = self . infcx . tcx . item_name ( def_id)
460+ && let Some ( hir_id) = hir_id
461+ && let expr = self . infcx . tcx . hir ( ) . expect_expr ( hir_id)
462+ && let hir:: ExprKind :: MethodCall ( _, rcvr, _, _) = expr. kind
463+ && let Some ( ty) = typeck_results. node_type_opt ( rcvr. hir_id )
464+ {
465+ // Look for all the possible implementations to suggest, otherwise we'll show
466+ // just suggest the syntax for the fully qualified path with placeholders.
467+ self . infcx . tcx . for_each_relevant_impl (
468+ self . infcx . tcx . parent ( def_id) , // Trait `DefId`
469+ ty, // `Self` type
470+ |impl_def_id| {
471+ let impl_args = self . fresh_args_for_item ( DUMMY_SP , impl_def_id) ;
472+ let impl_trait_ref = self
473+ . infcx
474+ . tcx
475+ . impl_trait_ref ( impl_def_id)
476+ . unwrap ( )
477+ . instantiate ( self . infcx . tcx , impl_args) ;
478+ let impl_self_ty = impl_trait_ref. self_ty ( ) ;
479+ if self . infcx . can_eq ( param_env, impl_self_ty, ty) {
480+ // The expr's self type could conform to this impl's self type.
481+ } else {
482+ // Nope, don't bother.
483+ return ;
484+ }
485+ let assocs = self . infcx . tcx . associated_items ( impl_def_id) ;
486+
487+ if self
488+ . infcx
489+ . tcx
490+ . is_diagnostic_item ( sym:: blanket_into_impl, impl_def_id)
491+ && let Some ( did) = self . infcx . tcx . get_diagnostic_item ( sym:: From )
492+ {
493+ let mut found = false ;
494+ self . infcx . tcx . for_each_impl ( did, |impl_def_id| {
495+ // We had an `<A as Into<B>::into` and we've hit the blanket
496+ // impl for `From<A>`. So we try and look for the right `From`
497+ // impls that *would* apply. We *could* do this in a generalized
498+ // version by evaluating the `where` clauses, but that would be
499+ // way too involved to implement. Instead we special case the
500+ // arguably most common case of `expr.into()`.
501+ let Some ( header) =
502+ self . infcx . tcx . impl_trait_header ( impl_def_id)
503+ else {
504+ return ;
505+ } ;
506+ let target = header. trait_ref . skip_binder ( ) . args . type_at ( 0 ) ;
507+ let _ty = header. trait_ref . skip_binder ( ) . args . type_at ( 1 ) ;
508+ if _ty == ty {
509+ paths. push ( format ! ( "{target}" ) ) ;
510+ found = true ;
511+ }
512+ } ) ;
513+ if found {
514+ return ;
515+ }
516+ }
517+
518+ // We're at the `impl` level, but we want to get the same method we
519+ // called *on this `impl`*, in order to get the right DefId and args.
520+ let Some ( assoc) = assocs. filter_by_name_unhygienic ( name) . next ( ) else {
521+ // The method isn't in this `impl`? Not useful to us then.
522+ return ;
523+ } ;
524+ // Let's ignore the generic params and replace them with `_` in the
525+ // suggested path.
526+ let identity_method = ty:: GenericArgs :: for_item (
527+ self . infcx . tcx ,
528+ assoc. def_id ,
529+ |param, _| {
530+ // We don't want to name the arguments, we just want to give an
531+ // idea of what the syntax is.
532+ match param. kind {
533+ ty:: GenericParamDefKind :: Lifetime => {
534+ self . infcx . tcx . lifetimes . re_erased . into ( )
535+ }
536+ ty:: GenericParamDefKind :: Type { .. } => {
537+ self . next_ty_var ( DUMMY_SP ) . into ( )
538+ }
539+ ty:: GenericParamDefKind :: Const { .. } => {
540+ self . next_const_var ( DUMMY_SP ) . into ( )
541+ }
542+ }
543+ } ,
544+ ) ;
545+ let fn_sig = self
546+ . infcx
547+ . tcx
548+ . fn_sig ( assoc. def_id )
549+ . instantiate ( self . infcx . tcx , identity_method) ;
550+ let ret = fn_sig. skip_binder ( ) . output ( ) ;
551+ paths. push ( format ! ( "{ret}" ) ) ;
552+ } ,
553+ ) ;
554+ }
555+
556+ if paths. is_empty ( ) {
557+ infer_subdiags. push ( SourceKindSubdiag :: LetLike {
558+ span : insert_span,
559+ name : pattern_name. map ( |name| name. to_string ( ) ) . unwrap_or_else ( String :: new) ,
560+ x_kind : arg_data. where_x_is_kind ( ty) ,
561+ prefix_kind : arg_data. kind . clone ( ) ,
562+ prefix : arg_data. kind . try_get_prefix ( ) . unwrap_or_default ( ) ,
563+ arg_name : arg_data. name ,
564+ kind : if pattern_name. is_some ( ) { "with_pattern" } else { "other" } ,
565+ type_name : ty_to_string ( self , ty, def_id) ,
566+ } ) ;
567+ } else {
568+ for type_name in paths {
569+ infer_subdiags. push ( SourceKindSubdiag :: LetLike {
570+ span : insert_span,
571+ name : pattern_name
572+ . map ( |name| name. to_string ( ) )
573+ . unwrap_or_else ( String :: new) ,
574+ x_kind : arg_data. where_x_is_kind ( ty) ,
575+ prefix_kind : arg_data. kind . clone ( ) ,
576+ prefix : arg_data. kind . try_get_prefix ( ) . unwrap_or_default ( ) ,
577+ arg_name : arg_data. name . clone ( ) ,
578+ kind : if pattern_name. is_some ( ) { "with_pattern" } else { "other" } ,
579+ type_name,
580+ } ) ;
581+ }
582+ }
466583 }
467584 InferSourceKind :: ClosureArg { insert_span, ty } => {
468585 infer_subdiags. push ( SourceKindSubdiag :: LetLike {
@@ -731,6 +848,7 @@ enum InferSourceKind<'tcx> {
731848 pattern_name : Option < Ident > ,
732849 ty : Ty < ' tcx > ,
733850 def_id : Option < DefId > ,
851+ hir_id : Option < HirId > ,
734852 } ,
735853 ClosureArg {
736854 insert_span : Span ,
@@ -916,8 +1034,11 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
9161034 let cost = self . source_cost ( & new_source) + self . attempt ;
9171035 debug ! ( ?cost) ;
9181036 self . attempt += 1 ;
919- if let Some ( InferSource { kind : InferSourceKind :: GenericArg { def_id : did, .. } , .. } ) =
920- self . infer_source
1037+ if let Some ( InferSource { kind : InferSourceKind :: GenericArg { def_id : did, .. } , .. } )
1038+ | Some ( InferSource {
1039+ kind : InferSourceKind :: FullyQualifiedMethodCall { def_id : did, .. } ,
1040+ ..
1041+ } ) = self . infer_source
9211042 && let InferSourceKind :: LetBinding { ref ty, ref mut def_id, .. } = new_source. kind
9221043 && ty. is_ty_or_numeric_infer ( )
9231044 {
@@ -1226,6 +1347,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
12261347 pattern_name : local. pat . simple_ident ( ) ,
12271348 ty,
12281349 def_id : None ,
1350+ hir_id : local. init . map ( |e| e. hir_id ) ,
12291351 } ,
12301352 } )
12311353 }
0 commit comments