@@ -2471,9 +2471,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24712471 ty:: RawPtr ( ..) => {
24722472 self . suggest_first_deref_field ( & mut err, expr, base, ident) ;
24732473 }
2474- ty:: Adt ( def, _) if !def. is_enum ( ) => {
2475- self . suggest_fields_on_recordish ( & mut err, expr, def, ident) ;
2476- }
24772474 ty:: Param ( param_ty) => {
24782475 self . point_at_param_definition ( & mut err, param_ty) ;
24792476 }
@@ -2633,34 +2630,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
26332630 err. span_label ( param_span, format ! ( "type parameter '{param_name}' declared here" ) ) ;
26342631 }
26352632
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-
26642633 fn maybe_suggest_array_indexing (
26652634 & self ,
26662635 err : & mut Diagnostic ,
@@ -2709,18 +2678,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
27092678
27102679 let mut err = type_error_struct ! (
27112680 self . tcx( ) . sess,
2712- field . span,
2681+ span,
27132682 expr_t,
27142683 E0609 ,
27152684 "no field `{field}` on type `{expr_t}`" ,
27162685 ) ;
27172686
27182687 // try to add a suggestion in case the field is a nested field of a field of the Adt
27192688 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 )
27222691 {
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 ( )
27242695 . filter_map ( |candidate_field| {
27252696 self . check_for_nested_field_satisfying (
27262697 span,
@@ -2729,6 +2700,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
27292700 args,
27302701 vec ! [ ] ,
27312702 mod_id,
2703+ id,
27322704 )
27332705 } )
27342706 . map ( |mut field_path| {
@@ -2753,6 +2725,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
27532725 candidate_fields. iter ( ) . map ( |path| format ! ( "{path}." ) ) ,
27542726 Applicability :: MaybeIncorrect ,
27552727 ) ;
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+ }
27562743 }
27572744 }
27582745 err
@@ -2781,33 +2768,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
27812768 span : Span ,
27822769 base_ty : Ty < ' tcx > ,
27832770 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 > ) > {
27852773 debug ! ( "get_field_candidates(span: {:?}, base_t: {:?}" , span, base_ty) ;
27862774
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+ ) ) ;
27972799 }
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 ,
28062801 }
2807- _ => { }
2808- }
2809- }
2810- None
2802+ } )
2803+ . collect ( )
28112804 }
28122805
28132806 /// This method is called after we have encountered a missing field error to recursively
@@ -2820,6 +2813,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
28202813 subst : GenericArgsRef < ' tcx > ,
28212814 mut field_path : Vec < Ident > ,
28222815 mod_id : DefId ,
2816+ hir_id : HirId ,
28232817 ) -> Option < Vec < Ident > > {
28242818 debug ! (
28252819 "check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}" ,
@@ -2835,20 +2829,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
28352829 let field_ty = candidate_field. ty ( self . tcx , subst) ;
28362830 if matches ( candidate_field, field_ty) {
28372831 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+ }
28522849 }
28532850 }
28542851 }
0 commit comments