@@ -452,17 +452,134 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
452
452
let mut infer_subdiags = Vec :: new ( ) ;
453
453
let mut multi_suggestions = Vec :: new ( ) ;
454
454
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
+ }
466
583
}
467
584
InferSourceKind :: ClosureArg { insert_span, ty } => {
468
585
infer_subdiags. push ( SourceKindSubdiag :: LetLike {
@@ -731,6 +848,7 @@ enum InferSourceKind<'tcx> {
731
848
pattern_name : Option < Ident > ,
732
849
ty : Ty < ' tcx > ,
733
850
def_id : Option < DefId > ,
851
+ hir_id : Option < HirId > ,
734
852
} ,
735
853
ClosureArg {
736
854
insert_span : Span ,
@@ -916,8 +1034,11 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
916
1034
let cost = self . source_cost ( & new_source) + self . attempt ;
917
1035
debug ! ( ?cost) ;
918
1036
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
921
1042
&& let InferSourceKind :: LetBinding { ref ty, ref mut def_id, .. } = new_source. kind
922
1043
&& ty. is_ty_or_numeric_infer ( )
923
1044
{
@@ -1226,6 +1347,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
1226
1347
pattern_name : local. pat . simple_ident ( ) ,
1227
1348
ty,
1228
1349
def_id : None ,
1350
+ hir_id : local. init . map ( |e| e. hir_id ) ,
1229
1351
} ,
1230
1352
} )
1231
1353
}
0 commit comments