@@ -2471,9 +2471,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2471
2471
ty:: RawPtr ( ..) => {
2472
2472
self . suggest_first_deref_field ( & mut err, expr, base, ident) ;
2473
2473
}
2474
- ty:: Adt ( def, _) if !def. is_enum ( ) => {
2475
- self . suggest_fields_on_recordish ( & mut err, expr, def, ident) ;
2476
- }
2477
2474
ty:: Param ( param_ty) => {
2478
2475
self . point_at_param_definition ( & mut err, param_ty) ;
2479
2476
}
@@ -2633,34 +2630,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2633
2630
err. span_label ( param_span, format ! ( "type parameter '{param_name}' declared here" ) ) ;
2634
2631
}
2635
2632
2636
- fn suggest_fields_on_recordish (
2637
- & self ,
2638
- err : & mut Diagnostic ,
2639
- expr : & hir:: Expr < ' _ > ,
2640
- def : ty:: AdtDef < ' tcx > ,
2641
- field : Ident ,
2642
- ) {
2643
- let available_field_names = self . available_field_names ( def. non_enum_variant ( ) , expr, & [ ] ) ;
2644
- if let Some ( suggested_field_name) =
2645
- find_best_match_for_name ( & available_field_names, field. name , None )
2646
- {
2647
- err. span_suggestion (
2648
- field. span ,
2649
- "a field with a similar name exists" ,
2650
- suggested_field_name,
2651
- Applicability :: MaybeIncorrect ,
2652
- ) ;
2653
- } else {
2654
- err. span_label ( field. span , "unknown field" ) ;
2655
- if !available_field_names. is_empty ( ) {
2656
- err. note ( format ! (
2657
- "available fields are: {}" ,
2658
- self . name_series_display( available_field_names) ,
2659
- ) ) ;
2660
- }
2661
- }
2662
- }
2663
-
2664
2633
fn maybe_suggest_array_indexing (
2665
2634
& self ,
2666
2635
err : & mut Diagnostic ,
@@ -2709,18 +2678,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2709
2678
2710
2679
let mut err = type_error_struct ! (
2711
2680
self . tcx( ) . sess,
2712
- field . span,
2681
+ span,
2713
2682
expr_t,
2714
2683
E0609 ,
2715
2684
"no field `{field}` on type `{expr_t}`" ,
2716
2685
) ;
2717
2686
2718
2687
// try to add a suggestion in case the field is a nested field of a field of the Adt
2719
2688
let mod_id = self . tcx . parent_module ( id) . to_def_id ( ) ;
2720
- if let Some ( ( fields , args) ) =
2721
- self . get_field_candidates_considering_privacy ( span, expr_t, mod_id)
2689
+ for ( found_fields , args) in
2690
+ self . get_field_candidates_considering_privacy ( span, expr_t, mod_id, id )
2722
2691
{
2723
- let candidate_fields: Vec < _ > = fields
2692
+ let field_names = found_fields. iter ( ) . map ( |field| field. name ) . collect :: < Vec < _ > > ( ) ;
2693
+ let candidate_fields: Vec < _ > = found_fields
2694
+ . into_iter ( )
2724
2695
. filter_map ( |candidate_field| {
2725
2696
self . check_for_nested_field_satisfying (
2726
2697
span,
@@ -2729,6 +2700,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2729
2700
args,
2730
2701
vec ! [ ] ,
2731
2702
mod_id,
2703
+ id,
2732
2704
)
2733
2705
} )
2734
2706
. map ( |mut field_path| {
@@ -2753,6 +2725,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2753
2725
candidate_fields. iter ( ) . map ( |path| format ! ( "{path}." ) ) ,
2754
2726
Applicability :: MaybeIncorrect ,
2755
2727
) ;
2728
+ } else {
2729
+ if let Some ( field_name) = find_best_match_for_name ( & field_names, field. name , None ) {
2730
+ err. span_suggestion (
2731
+ field. span ,
2732
+ "a field with a similar name exists" ,
2733
+ field_name,
2734
+ Applicability :: MaybeIncorrect ,
2735
+ ) ;
2736
+ } else if !field_names. is_empty ( ) {
2737
+ let is = if field_names. len ( ) == 1 { " is" } else { "s are" } ;
2738
+ err. note ( format ! (
2739
+ "available field{is}: {}" ,
2740
+ self . name_series_display( field_names) ,
2741
+ ) ) ;
2742
+ }
2756
2743
}
2757
2744
}
2758
2745
err
@@ -2781,33 +2768,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2781
2768
span : Span ,
2782
2769
base_ty : Ty < ' tcx > ,
2783
2770
mod_id : DefId ,
2784
- ) -> Option < ( impl Iterator < Item = & ' tcx ty:: FieldDef > + ' tcx , GenericArgsRef < ' tcx > ) > {
2771
+ hir_id : hir:: HirId ,
2772
+ ) -> Vec < ( Vec < & ' tcx ty:: FieldDef > , GenericArgsRef < ' tcx > ) > {
2785
2773
debug ! ( "get_field_candidates(span: {:?}, base_t: {:?}" , span, base_ty) ;
2786
2774
2787
- for ( base_t, _) in self . autoderef ( span, base_ty) {
2788
- match base_t. kind ( ) {
2789
- ty:: Adt ( base_def, args) if !base_def. is_enum ( ) => {
2790
- let tcx = self . tcx ;
2791
- let fields = & base_def. non_enum_variant ( ) . fields ;
2792
- // Some struct, e.g. some that impl `Deref`, have all private fields
2793
- // because you're expected to deref them to access the _real_ fields.
2794
- // This, for example, will help us suggest accessing a field through a `Box<T>`.
2795
- if fields. iter ( ) . all ( |field| !field. vis . is_accessible_from ( mod_id, tcx) ) {
2796
- continue ;
2775
+ self . autoderef ( span, base_ty)
2776
+ . filter_map ( move |( base_t, _) | {
2777
+ match base_t. kind ( ) {
2778
+ ty:: Adt ( base_def, args) if !base_def. is_enum ( ) => {
2779
+ let tcx = self . tcx ;
2780
+ let fields = & base_def. non_enum_variant ( ) . fields ;
2781
+ // Some struct, e.g. some that impl `Deref`, have all private fields
2782
+ // because you're expected to deref them to access the _real_ fields.
2783
+ // This, for example, will help us suggest accessing a field through a `Box<T>`.
2784
+ if fields. iter ( ) . all ( |field| !field. vis . is_accessible_from ( mod_id, tcx) ) {
2785
+ return None ;
2786
+ }
2787
+ return Some ( (
2788
+ fields
2789
+ . iter ( )
2790
+ . filter ( move |field| {
2791
+ field. vis . is_accessible_from ( mod_id, tcx)
2792
+ && self . is_field_suggestable ( field, hir_id, span)
2793
+ } )
2794
+ // For compile-time reasons put a limit on number of fields we search
2795
+ . take ( 100 )
2796
+ . collect :: < Vec < _ > > ( ) ,
2797
+ * args,
2798
+ ) ) ;
2797
2799
}
2798
- return Some ( (
2799
- fields
2800
- . iter ( )
2801
- . filter ( move |field| field. vis . is_accessible_from ( mod_id, tcx) )
2802
- // For compile-time reasons put a limit on number of fields we search
2803
- . take ( 100 ) ,
2804
- args,
2805
- ) ) ;
2800
+ _ => None ,
2806
2801
}
2807
- _ => { }
2808
- }
2809
- }
2810
- None
2802
+ } )
2803
+ . collect ( )
2811
2804
}
2812
2805
2813
2806
/// This method is called after we have encountered a missing field error to recursively
@@ -2820,6 +2813,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2820
2813
subst : GenericArgsRef < ' tcx > ,
2821
2814
mut field_path : Vec < Ident > ,
2822
2815
mod_id : DefId ,
2816
+ hir_id : HirId ,
2823
2817
) -> Option < Vec < Ident > > {
2824
2818
debug ! (
2825
2819
"check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}" ,
@@ -2835,20 +2829,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2835
2829
let field_ty = candidate_field. ty ( self . tcx , subst) ;
2836
2830
if matches ( candidate_field, field_ty) {
2837
2831
return Some ( field_path) ;
2838
- } else if let Some ( ( nested_fields, subst) ) =
2839
- self . get_field_candidates_considering_privacy ( span, field_ty, mod_id)
2840
- {
2841
- // recursively search fields of `candidate_field` if it's a ty::Adt
2842
- for field in nested_fields {
2843
- if let Some ( field_path) = self . check_for_nested_field_satisfying (
2844
- span,
2845
- matches,
2846
- field,
2847
- subst,
2848
- field_path. clone ( ) ,
2849
- mod_id,
2850
- ) {
2851
- return Some ( field_path) ;
2832
+ } else {
2833
+ for ( nested_fields, subst) in
2834
+ self . get_field_candidates_considering_privacy ( span, field_ty, mod_id, hir_id)
2835
+ {
2836
+ // recursively search fields of `candidate_field` if it's a ty::Adt
2837
+ for field in nested_fields {
2838
+ if let Some ( field_path) = self . check_for_nested_field_satisfying (
2839
+ span,
2840
+ matches,
2841
+ field,
2842
+ subst,
2843
+ field_path. clone ( ) ,
2844
+ mod_id,
2845
+ hir_id,
2846
+ ) {
2847
+ return Some ( field_path) ;
2848
+ }
2852
2849
}
2853
2850
}
2854
2851
}
0 commit comments