@@ -455,124 +455,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
455455 InferSourceKind :: LetBinding { insert_span, pattern_name, ty, def_id, hir_id } => {
456456 let mut paths = vec ! [ ] ;
457457 if let Some ( def_id) = def_id
458- && let name = self . infcx . tcx . item_name ( def_id)
459458 && let Some ( hir_id) = hir_id
460459 && let expr = self . infcx . tcx . hir ( ) . expect_expr ( hir_id)
461460 && let hir:: ExprKind :: MethodCall ( _, rcvr, _, _) = expr. kind
462461 && let Some ( ty) = typeck_results. node_type_opt ( rcvr. hir_id )
463462 {
464- // Look for all the possible implementations to suggest, otherwise we'll show
465- // just suggest the syntax for the fully qualified path with placeholders.
466- self . infcx . tcx . for_each_relevant_impl (
467- self . infcx . tcx . parent ( def_id) , // Trait `DefId`
468- ty, // `Self` type
469- |impl_def_id| {
470- let impl_args = ty:: GenericArgs :: for_item (
471- self . infcx . tcx ,
472- impl_def_id,
473- |param, _| {
474- // We don't want to name the arguments, we just want to give an
475- // idea of what the syntax is.
476- match param. kind {
477- ty:: GenericParamDefKind :: Lifetime => {
478- self . infcx . tcx . lifetimes . re_erased . into ( )
479- }
480- ty:: GenericParamDefKind :: Type { .. } => {
481- self . next_ty_var ( DUMMY_SP ) . into ( )
482- }
483- ty:: GenericParamDefKind :: Const { .. } => {
484- self . next_const_var ( DUMMY_SP ) . into ( )
485- }
486- }
487- } ,
488- ) ;
489- let impl_trait_ref = self
490- . infcx
491- . tcx
492- . impl_trait_ref ( impl_def_id)
493- . unwrap ( )
494- . instantiate ( self . infcx . tcx , impl_args) ;
495- let impl_self_ty = impl_trait_ref. self_ty ( ) ;
496- if self . infcx . can_eq ( param_env, impl_self_ty, ty) {
497- // The expr's self type could conform to this impl's self type.
498- } else {
499- // Nope, don't bother.
500- return ;
501- }
502- let assocs = self . infcx . tcx . associated_items ( impl_def_id) ;
503-
504- if self
505- . infcx
506- . tcx
507- . is_diagnostic_item ( sym:: blanket_into_impl, impl_def_id)
508- && let Some ( did) = self . infcx . tcx . get_diagnostic_item ( sym:: From )
509- {
510- let mut found = false ;
511- self . infcx . tcx . for_each_impl ( did, |impl_def_id| {
512- // We had an `<A as Into<B>::into` and we've hit the blanket
513- // impl for `From<A>`. So we try and look for the right `From`
514- // impls that *would* apply. We *could* do this in a generalized
515- // version by evaluating the `where` clauses, but that would be
516- // way too involved to implement. Instead we special case the
517- // arguably most common case of `expr.into()`.
518- let Some ( header) =
519- self . infcx . tcx . impl_trait_header ( impl_def_id)
520- else {
521- return ;
522- } ;
523- let target = header. trait_ref . skip_binder ( ) . args . type_at ( 0 ) ;
524- let _ty = header. trait_ref . skip_binder ( ) . args . type_at ( 1 ) ;
525- if _ty == ty {
526- paths. push ( format ! ( "{target}" ) ) ;
527- found = true ;
528- }
529- } ) ;
530- if found {
531- return ;
532- }
533- }
534-
535- // We're at the `impl` level, but we want to get the same method we
536- // called *on this `impl`*, in order to get the right DefId and args.
537- let Some ( assoc) = assocs. filter_by_name_unhygienic ( name) . next ( ) else {
538- // The method isn't in this `impl`? Not useful to us then.
539- return ;
540- } ;
541- let Some ( trait_assoc_item) = assoc. trait_item_def_id else {
542- return ;
543- } ;
544- // Let's ignore the generic params and replace them with `_` in the
545- // suggested path.
546- let trait_assoc_substs = impl_trait_ref. args . extend_to (
547- self . infcx . tcx ,
548- trait_assoc_item,
549- |def, _| {
550- // We don't want to name the arguments, we just want to give an
551- // idea of what the syntax is.
552- match def. kind {
553- ty:: GenericParamDefKind :: Lifetime => {
554- self . infcx . tcx . lifetimes . re_erased . into ( )
555- }
556- ty:: GenericParamDefKind :: Type { .. } => {
557- self . next_ty_var ( DUMMY_SP ) . into ( )
558- }
559- ty:: GenericParamDefKind :: Const { .. } => {
560- self . next_const_var ( DUMMY_SP ) . into ( )
561- }
562- }
563- } ,
564- ) ;
565- let identity_method =
566- impl_args. rebase_onto ( self . infcx . tcx , def_id, trait_assoc_substs) ;
567- let fn_sig = self
568- . infcx
569- . tcx
570- . fn_sig ( def_id)
571- . instantiate ( self . infcx . tcx , identity_method) ;
572- let ret = fn_sig. skip_binder ( ) . output ( ) ;
573- paths. push ( format ! ( "{ret}" ) ) ;
574- } ,
575- ) ;
463+ paths = self . get_suggestions ( ty, def_id, true , param_env, None ) ;
576464 }
577465
578466 if paths. is_empty ( ) {
@@ -697,114 +585,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
697585 _ => "" ,
698586 } ;
699587
700- let mut paths = vec ! [ ] ;
701- let name = self . infcx . tcx . item_name ( def_id) ;
702588 // Look for all the possible implementations to suggest, otherwise we'll show
703589 // just suggest the syntax for the fully qualified path with placeholders.
704- self . infcx . tcx . for_each_relevant_impl (
705- self . infcx . tcx . parent ( def_id) , // Trait `DefId`
706- args. type_at ( 0 ) , // `Self` type
707- |impl_def_id| {
708- let impl_args = ty:: GenericArgs :: for_item (
709- self . infcx . tcx ,
710- impl_def_id,
711- |param, _| {
712- // We don't want to name the arguments, we just want to give an
713- // idea of what the syntax is.
714- match param. kind {
715- ty:: GenericParamDefKind :: Lifetime => {
716- self . infcx . tcx . lifetimes . re_erased . into ( )
717- }
718- ty:: GenericParamDefKind :: Type { .. } => {
719- self . next_ty_var ( DUMMY_SP ) . into ( )
720- }
721- ty:: GenericParamDefKind :: Const { .. } => {
722- self . next_const_var ( DUMMY_SP ) . into ( )
723- }
724- }
725- } ,
726- ) ;
727- let impl_trait_ref = self
728- . infcx
729- . tcx
730- . impl_trait_ref ( impl_def_id)
731- . unwrap ( )
732- . instantiate ( self . infcx . tcx , impl_args) ;
733- let impl_self_ty = impl_trait_ref. self_ty ( ) ;
734- if self . infcx . can_eq ( param_env, impl_self_ty, args. type_at ( 0 ) ) {
735- // The expr's self type could conform to this impl's self type.
736- } else {
737- // Nope, don't bother.
738- return ;
739- }
740- let assocs = self . infcx . tcx . associated_items ( impl_def_id) ;
741-
742- if self
743- . infcx
744- . tcx
745- . is_diagnostic_item ( sym:: blanket_into_impl, impl_def_id)
746- && let Some ( did) = self . infcx . tcx . get_diagnostic_item ( sym:: From )
747- {
748- let mut found = false ;
749- self . infcx . tcx . for_each_impl ( did, |impl_def_id| {
750- // We had an `<A as Into<B>::into` and we've hit the blanket
751- // impl for `From<A>`. So we try and look for the right `From`
752- // impls that *would* apply. We *could* do this in a generalized
753- // version by evaluating the `where` clauses, but that would be
754- // way too involved to implement. Instead we special case the
755- // arguably most common case of `expr.into()`.
756- let Some ( header) =
757- self . infcx . tcx . impl_trait_header ( impl_def_id)
758- else {
759- return ;
760- } ;
761- let target = header. trait_ref . skip_binder ( ) . args . type_at ( 0 ) ;
762- let ty = header. trait_ref . skip_binder ( ) . args . type_at ( 1 ) ;
763- if ty == args. type_at ( 0 ) {
764- paths. push ( format ! ( "<{ty} as Into<{target}>>::into" ) ) ;
765- found = true ;
766- }
767- } ) ;
768- if found {
769- return ;
770- }
771- }
772-
773- // We're at the `impl` level, but we want to get the same method we
774- // called *on this `impl`*, in order to get the right DefId and args.
775- let Some ( assoc) = assocs. filter_by_name_unhygienic ( name) . next ( ) else {
776- // The method isn't in this `impl`? Not useful to us then.
777- return ;
778- } ;
779- let Some ( trait_assoc_item) = assoc. trait_item_def_id else {
780- return ;
781- } ;
782- let trait_assoc_substs = impl_trait_ref. args . extend_to (
783- self . infcx . tcx ,
784- trait_assoc_item,
785- |def, _| {
786- // We don't want to name the arguments, we just want to give an
787- // idea of what the syntax is.
788- match def. kind {
789- ty:: GenericParamDefKind :: Lifetime => {
790- self . infcx . tcx . lifetimes . re_erased . into ( )
791- }
792- ty:: GenericParamDefKind :: Type { .. } => {
793- self . next_ty_var ( DUMMY_SP ) . into ( )
794- }
795- ty:: GenericParamDefKind :: Const { .. } => {
796- self . next_const_var ( DUMMY_SP ) . into ( )
797- }
798- }
799- } ,
800- ) ;
801- let identity_method =
802- args. rebase_onto ( self . infcx . tcx , def_id, trait_assoc_substs) ;
803- let mut printer = fmt_printer ( self , Namespace :: ValueNS ) ;
804- printer. print_def_path ( def_id, identity_method) . unwrap ( ) ;
805- paths. push ( printer. into_buffer ( ) ) ;
806- } ,
807- ) ;
590+ let paths =
591+ self . get_suggestions ( args. type_at ( 0 ) , def_id, false , param_env, Some ( args) ) ;
808592 if paths. len ( ) > 20 || paths. is_empty ( ) {
809593 // This will show the fallback impl, so the expression will have type
810594 // parameter placeholders, but it's better than nothing.
@@ -875,6 +659,113 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
875659 } ) ,
876660 }
877661 }
662+
663+ fn get_suggestions (
664+ & self ,
665+ ty : Ty < ' tcx > , // args.type_at(0) / ty
666+ def_id : DefId ,
667+ target_type : bool , // false / true
668+ param_env : ty:: ParamEnv < ' tcx > ,
669+ args : Option < & ty:: GenericArgs < ' tcx > > ,
670+ ) -> Vec < String > {
671+ let tcx = self . infcx . tcx ;
672+ let mut paths = vec ! [ ] ;
673+ let name = tcx. item_name ( def_id) ;
674+ let empty_args = |def_id| {
675+ ty:: GenericArgs :: for_item ( tcx, def_id, |param, _| {
676+ // We don't want to name the arguments, we just want to give an
677+ // idea of what the syntax is.
678+ match param. kind {
679+ ty:: GenericParamDefKind :: Lifetime => tcx. lifetimes . re_erased . into ( ) ,
680+ ty:: GenericParamDefKind :: Type { .. } => self . next_ty_var ( DUMMY_SP ) . into ( ) ,
681+ ty:: GenericParamDefKind :: Const { .. } => self . next_const_var ( DUMMY_SP ) . into ( ) ,
682+ }
683+ } )
684+ } ;
685+ let args = args. unwrap_or_else ( || empty_args ( def_id) ) ;
686+ tcx. for_each_relevant_impl (
687+ tcx. parent ( def_id) , // Trait `DefId`
688+ ty, // `Self` type
689+ |impl_def_id| {
690+ let impl_args = empty_args ( impl_def_id) ;
691+ let impl_trait_ref =
692+ tcx. impl_trait_ref ( impl_def_id) . unwrap ( ) . instantiate ( tcx, impl_args) ;
693+ let impl_self_ty = impl_trait_ref. self_ty ( ) ;
694+ if self . infcx . can_eq ( param_env, impl_self_ty, ty) {
695+ // The expr's self type could conform to this impl's self type.
696+ } else {
697+ // Nope, don't bother.
698+ return ;
699+ }
700+ let assocs = tcx. associated_items ( impl_def_id) ;
701+
702+ if tcx. is_diagnostic_item ( sym:: blanket_into_impl, impl_def_id)
703+ && let Some ( did) = tcx. get_diagnostic_item ( sym:: From )
704+ {
705+ let mut found = false ;
706+ tcx. for_each_impl ( did, |impl_def_id| {
707+ // We had an `<A as Into<B>::into` and we've hit the blanket
708+ // impl for `From<A>`. So we try and look for the right `From`
709+ // impls that *would* apply. We *could* do this in a generalized
710+ // version by evaluating the `where` clauses, but that would be
711+ // way too involved to implement. Instead we special case the
712+ // arguably most common case of `expr.into()`.
713+ let Some ( header) = tcx. impl_trait_header ( impl_def_id) else {
714+ return ;
715+ } ;
716+ let target = header. trait_ref . skip_binder ( ) . args . type_at ( 0 ) ;
717+ let _ty = header. trait_ref . skip_binder ( ) . args . type_at ( 1 ) ;
718+ if _ty == ty {
719+ if target_type {
720+ paths. push ( format ! ( "{target}" ) ) ;
721+ } else {
722+ paths. push ( format ! ( "<{ty} as Into<{target}>>::into" ) ) ;
723+ }
724+ found = true ;
725+ }
726+ } ) ;
727+ if found {
728+ return ;
729+ }
730+ }
731+
732+ // We're at the `impl` level, but we want to get the same method we
733+ // called *on this `impl`*, in order to get the right DefId and args.
734+ let Some ( assoc) = assocs. filter_by_name_unhygienic ( name) . next ( ) else {
735+ // The method isn't in this `impl`? Not useful to us then.
736+ return ;
737+ } ;
738+ let Some ( trait_assoc_item) = assoc. trait_item_def_id else {
739+ return ;
740+ } ;
741+ let trait_assoc_substs =
742+ impl_trait_ref. args . extend_to ( tcx, trait_assoc_item, |def, _| {
743+ // We don't want to name the arguments, we just want to give an
744+ // idea of what the syntax is.
745+ match def. kind {
746+ ty:: GenericParamDefKind :: Lifetime => tcx. lifetimes . re_erased . into ( ) ,
747+ ty:: GenericParamDefKind :: Type { .. } => {
748+ self . next_ty_var ( DUMMY_SP ) . into ( )
749+ }
750+ ty:: GenericParamDefKind :: Const { .. } => {
751+ self . next_const_var ( DUMMY_SP ) . into ( )
752+ }
753+ }
754+ } ) ;
755+ let identity_method = args. rebase_onto ( tcx, def_id, trait_assoc_substs) ;
756+ if target_type {
757+ let fn_sig = tcx. fn_sig ( def_id) . instantiate ( tcx, identity_method) ;
758+ let ret = fn_sig. skip_binder ( ) . output ( ) ;
759+ paths. push ( format ! ( "{ret}" ) ) ;
760+ } else {
761+ let mut printer = fmt_printer ( self , Namespace :: ValueNS ) ;
762+ printer. print_def_path ( def_id, identity_method) . unwrap ( ) ;
763+ paths. push ( printer. into_buffer ( ) ) ;
764+ }
765+ } ,
766+ ) ;
767+ paths
768+ }
878769}
879770
880771#[ derive( Debug ) ]
0 commit comments