@@ -455,124 +455,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
455
455
InferSourceKind :: LetBinding { insert_span, pattern_name, ty, def_id, hir_id } => {
456
456
let mut paths = vec ! [ ] ;
457
457
if let Some ( def_id) = def_id
458
- && let name = self . infcx . tcx . item_name ( def_id)
459
458
&& let Some ( hir_id) = hir_id
460
459
&& let expr = self . infcx . tcx . hir ( ) . expect_expr ( hir_id)
461
460
&& let hir:: ExprKind :: MethodCall ( _, rcvr, _, _) = expr. kind
462
461
&& let Some ( ty) = typeck_results. node_type_opt ( rcvr. hir_id )
463
462
{
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 ) ;
576
464
}
577
465
578
466
if paths. is_empty ( ) {
@@ -697,114 +585,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
697
585
_ => "" ,
698
586
} ;
699
587
700
- let mut paths = vec ! [ ] ;
701
- let name = self . infcx . tcx . item_name ( def_id) ;
702
588
// Look for all the possible implementations to suggest, otherwise we'll show
703
589
// 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) ) ;
808
592
if paths. len ( ) > 20 || paths. is_empty ( ) {
809
593
// This will show the fallback impl, so the expression will have type
810
594
// parameter placeholders, but it's better than nothing.
@@ -875,6 +659,113 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
875
659
} ) ,
876
660
}
877
661
}
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
+ }
878
769
}
879
770
880
771
#[ derive( Debug ) ]
0 commit comments