@@ -791,12 +791,30 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
791791 }
792792}
793793
794+ fn find_field ( tcx : TyCtxt < ' _ > , ( def_id, ident) : ( DefId , Ident ) ) -> Option < FieldIdx > {
795+ tcx. adt_def ( def_id) . non_enum_variant ( ) . fields . iter_enumerated ( ) . find_map ( |( idx, field) | {
796+ if field. is_unnamed ( ) {
797+ let field_ty = tcx. type_of ( field. did ) . instantiate_identity ( ) ;
798+ let adt_def = field_ty. ty_adt_def ( ) . expect ( "expect Adt for unnamed field" ) ;
799+ tcx. find_field ( ( adt_def. did ( ) , ident) ) . map ( |_| idx)
800+ } else {
801+ ( field. ident ( tcx) . normalize_to_macros_2_0 ( ) == ident) . then_some ( idx)
802+ }
803+ } )
804+ }
805+
794806#[ derive( Clone , Copy ) ]
795807struct NestedSpan {
796808 span : Span ,
797809 nested_field_span : Span ,
798810}
799811
812+ impl NestedSpan {
813+ fn to_field_already_declared_nested_help ( & self ) -> errors:: FieldAlreadyDeclaredNestedHelp {
814+ errors:: FieldAlreadyDeclaredNestedHelp { span : self . span }
815+ }
816+ }
817+
800818#[ derive( Clone , Copy ) ]
801819enum FieldDeclSpan {
802820 NotNested ( Span ) ,
@@ -815,87 +833,131 @@ impl From<NestedSpan> for FieldDeclSpan {
815833 }
816834}
817835
818- /// Check the uniqueness of fields across adt where there are
819- /// nested fields imported from an unnamed field.
820- fn check_field_uniqueness_in_nested_adt (
821- tcx : TyCtxt < ' _ > ,
822- adt_def : ty:: AdtDef < ' _ > ,
823- check : & mut impl FnMut ( Ident , /* nested_field_span */ Span ) ,
824- ) {
825- for field in adt_def. all_fields ( ) {
826- if field. is_unnamed ( ) {
827- // Here we don't care about the generic parameters, so `instantiate_identity` is enough.
828- match tcx. type_of ( field. did ) . instantiate_identity ( ) . kind ( ) {
829- ty:: Adt ( adt_def, _) => {
830- check_field_uniqueness_in_nested_adt ( tcx, * adt_def, & mut * check) ;
836+ struct FieldUniquenessCheckContext < ' tcx > {
837+ tcx : TyCtxt < ' tcx > ,
838+ seen_fields : FxHashMap < Ident , FieldDeclSpan > ,
839+ }
840+
841+ impl < ' tcx > FieldUniquenessCheckContext < ' tcx > {
842+ fn new ( tcx : TyCtxt < ' tcx > ) -> Self {
843+ Self { tcx, seen_fields : FxHashMap :: default ( ) }
844+ }
845+
846+ /// Check if a given field `ident` declared at `field_decl` has been declared elsewhere before.
847+ fn check_field_decl ( & mut self , ident : Ident , field_decl : FieldDeclSpan ) {
848+ use FieldDeclSpan :: * ;
849+ let field_name = ident. name ;
850+ let ident = ident. normalize_to_macros_2_0 ( ) ;
851+ match ( field_decl, self . seen_fields . get ( & ident) . copied ( ) ) {
852+ ( NotNested ( span) , Some ( NotNested ( prev_span) ) ) => {
853+ self . tcx . dcx ( ) . emit_err ( errors:: FieldAlreadyDeclared :: NotNested {
854+ field_name,
855+ span,
856+ prev_span,
857+ } ) ;
858+ }
859+ ( NotNested ( span) , Some ( Nested ( prev) ) ) => {
860+ self . tcx . dcx ( ) . emit_err ( errors:: FieldAlreadyDeclared :: PreviousNested {
861+ field_name,
862+ span,
863+ prev_span : prev. span ,
864+ prev_nested_field_span : prev. nested_field_span ,
865+ prev_help : prev. to_field_already_declared_nested_help ( ) ,
866+ } ) ;
867+ }
868+ (
869+ Nested ( current @ NestedSpan { span, nested_field_span, .. } ) ,
870+ Some ( NotNested ( prev_span) ) ,
871+ ) => {
872+ self . tcx . dcx ( ) . emit_err ( errors:: FieldAlreadyDeclared :: CurrentNested {
873+ field_name,
874+ span,
875+ nested_field_span,
876+ help : current. to_field_already_declared_nested_help ( ) ,
877+ prev_span,
878+ } ) ;
879+ }
880+ ( Nested ( current @ NestedSpan { span, nested_field_span } ) , Some ( Nested ( prev) ) ) => {
881+ self . tcx . dcx ( ) . emit_err ( errors:: FieldAlreadyDeclared :: BothNested {
882+ field_name,
883+ span,
884+ nested_field_span,
885+ help : current. to_field_already_declared_nested_help ( ) ,
886+ prev_span : prev. span ,
887+ prev_nested_field_span : prev. nested_field_span ,
888+ prev_help : prev. to_field_already_declared_nested_help ( ) ,
889+ } ) ;
890+ }
891+ ( field_decl, None ) => {
892+ self . seen_fields . insert ( ident, field_decl) ;
893+ }
894+ }
895+ }
896+
897+ /// Check the uniqueness of fields across adt where there are
898+ /// nested fields imported from an unnamed field.
899+ fn check_field_in_nested_adt ( & mut self , adt_def : ty:: AdtDef < ' _ > , unnamed_field_span : Span ) {
900+ for field in adt_def. all_fields ( ) {
901+ if field. is_unnamed ( ) {
902+ // Here we don't care about the generic parameters, so `instantiate_identity` is enough.
903+ match self . tcx . type_of ( field. did ) . instantiate_identity ( ) . kind ( ) {
904+ ty:: Adt ( adt_def, _) => {
905+ self . check_field_in_nested_adt ( * adt_def, unnamed_field_span) ;
906+ }
907+ ty_kind => span_bug ! (
908+ self . tcx. def_span( field. did) ,
909+ "Unexpected TyKind in FieldUniquenessCheckContext::check_field_in_nested_adt(): {ty_kind:?}"
910+ ) ,
831911 }
832- ty_kind => bug ! (
833- "Unexpected ty kind in check_field_uniqueness_in_nested_adt(): {ty_kind:?}"
834- ) ,
912+ } else {
913+ self . check_field_decl (
914+ field. ident ( self . tcx ) ,
915+ NestedSpan {
916+ span : unnamed_field_span,
917+ nested_field_span : self . tcx . def_span ( field. did ) ,
918+ }
919+ . into ( ) ,
920+ ) ;
835921 }
836- } else {
837- check ( field. ident ( tcx) , tcx. def_span ( field. did ) ) ;
838922 }
839923 }
840- }
841924
842- /// Check the uniqueness of fields in a struct variant, and recursively
843- /// check the nested fields if it is an unnamed field with type of an
844- /// annoymous adt.
845- fn check_field_uniqueness (
846- tcx : TyCtxt < ' _ > ,
847- field : & hir:: FieldDef < ' _ > ,
848- check : & mut impl FnMut ( Ident , FieldDeclSpan ) ,
849- ) {
850- if field. ident . name == kw:: Underscore {
851- let ty_span = field. ty . span ;
925+ /// Check the uniqueness of fields in a struct variant, and recursively
926+ /// check the nested fields if it is an unnamed field with type of an
927+ /// annoymous adt.
928+ fn check_field ( & mut self , field : & hir:: FieldDef < ' _ > ) {
929+ if field. ident . name != kw:: Underscore {
930+ self . check_field_decl ( field. ident , field. span . into ( ) ) ;
931+ return ;
932+ }
852933 match & field. ty . kind {
853934 hir:: TyKind :: AnonAdt ( item_id) => {
854- match & tcx. hir_node ( item_id. hir_id ( ) ) . expect_item ( ) . kind {
935+ match & self . tcx . hir_node ( item_id. hir_id ( ) ) . expect_item ( ) . kind {
855936 hir:: ItemKind :: Struct ( variant_data, ..)
856937 | hir:: ItemKind :: Union ( variant_data, ..) => {
857- variant_data
858- . fields ( )
859- . iter ( )
860- . for_each ( |f| check_field_uniqueness ( tcx, f, & mut * check) ) ;
938+ variant_data. fields ( ) . iter ( ) . for_each ( |f| self . check_field ( f) ) ;
861939 }
862940 item_kind => span_bug ! (
863- ty_span ,
864- "Unexpected item kind in check_field_uniqueness (): {item_kind:?}"
941+ field . ty . span ,
942+ "Unexpected ItemKind in FieldUniquenessCheckContext::check_field (): {item_kind:?}"
865943 ) ,
866944 }
867945 }
868946 hir:: TyKind :: Path ( hir:: QPath :: Resolved ( _, hir:: Path { res, .. } ) ) => {
869- check_field_uniqueness_in_nested_adt (
870- tcx,
871- tcx. adt_def ( res. def_id ( ) ) ,
872- & mut |ident, nested_field_span| {
873- check ( ident, NestedSpan { span : field. span , nested_field_span } . into ( ) )
874- } ,
875- ) ;
947+ self . check_field_in_nested_adt ( self . tcx . adt_def ( res. def_id ( ) ) , field. span ) ;
876948 }
877949 // Abort due to errors (there must be an error if an unnamed field
878950 // has any type kind other than an anonymous adt or a named adt)
879- _ => {
880- debug_assert ! ( tcx. dcx( ) . has_errors( ) . is_some( ) ) ;
881- tcx. dcx ( ) . abort_if_errors ( )
951+ ty_kind => {
952+ self . tcx . dcx ( ) . span_delayed_bug (
953+ field. ty . span ,
954+ format ! ( "Unexpected TyKind in FieldUniquenessCheckContext::check_field(): {ty_kind:?}" ) ,
955+ ) ;
956+ // FIXME: errors during AST validation should abort the compilation before reaching here.
957+ self . tcx . dcx ( ) . abort_if_errors ( ) ;
882958 }
883959 }
884- return ;
885960 }
886- check ( field. ident , field. span . into ( ) ) ;
887- }
888-
889- fn find_field ( tcx : TyCtxt < ' _ > , ( def_id, ident) : ( DefId , Ident ) ) -> Option < FieldIdx > {
890- tcx. adt_def ( def_id) . non_enum_variant ( ) . fields . iter_enumerated ( ) . find_map ( |( idx, field) | {
891- if field. is_unnamed ( ) {
892- let field_ty = tcx. type_of ( field. did ) . instantiate_identity ( ) ;
893- let adt_def = field_ty. ty_adt_def ( ) . expect ( "expect Adt for unnamed field" ) ;
894- tcx. find_field ( ( adt_def. did ( ) , ident) ) . map ( |_| idx)
895- } else {
896- ( field. ident ( tcx) . normalize_to_macros_2_0 ( ) == ident) . then_some ( idx)
897- }
898- } )
899961}
900962
901963fn convert_variant (
@@ -909,58 +971,16 @@ fn convert_variant(
909971 is_anonymous : bool ,
910972) -> ty:: VariantDef {
911973 let mut has_unnamed_fields = false ;
912- let mut seen_fields : FxHashMap < Ident , FieldDeclSpan > = Default :: default ( ) ;
974+ let mut field_uniqueness_check_ctx = FieldUniquenessCheckContext :: new ( tcx ) ;
913975 let fields = def
914976 . fields ( )
915977 . iter ( )
916978 . inspect ( |f| {
917979 has_unnamed_fields |= f. ident . name == kw:: Underscore ;
980+ // We only check named ADT here because anonymous ADTs are checked inside
981+ // the nammed ADT in which they are defined.
918982 if !is_anonymous {
919- check_field_uniqueness ( tcx, f, & mut |ident, field_decl| {
920- use FieldDeclSpan :: * ;
921- let field_name = ident. name ;
922- let ident = ident. normalize_to_macros_2_0 ( ) ;
923- match ( field_decl, seen_fields. get ( & ident) . copied ( ) ) {
924- ( NotNested ( span) , Some ( NotNested ( prev_span) ) ) => {
925- tcx. dcx ( ) . emit_err ( errors:: FieldAlreadyDeclared :: NotNested {
926- field_name,
927- span,
928- prev_span,
929- } ) ;
930- }
931- ( NotNested ( span) , Some ( Nested ( prev) ) ) => {
932- tcx. dcx ( ) . emit_err ( errors:: FieldAlreadyDeclared :: PreviousNested {
933- field_name,
934- span,
935- prev_span : prev. span ,
936- prev_nested_field_span : prev. nested_field_span ,
937- } ) ;
938- }
939- (
940- Nested ( NestedSpan { span, nested_field_span } ) ,
941- Some ( NotNested ( prev_span) ) ,
942- ) => {
943- tcx. dcx ( ) . emit_err ( errors:: FieldAlreadyDeclared :: CurrentNested {
944- field_name,
945- span,
946- nested_field_span,
947- prev_span,
948- } ) ;
949- }
950- ( Nested ( NestedSpan { span, nested_field_span } ) , Some ( Nested ( prev) ) ) => {
951- tcx. dcx ( ) . emit_err ( errors:: FieldAlreadyDeclared :: BothNested {
952- field_name,
953- span,
954- nested_field_span,
955- prev_span : prev. span ,
956- prev_nested_field_span : prev. nested_field_span ,
957- } ) ;
958- }
959- ( field_decl, None ) => {
960- seen_fields. insert ( ident, field_decl) ;
961- }
962- }
963- } ) ;
983+ field_uniqueness_check_ctx. check_field ( f) ;
964984 }
965985 } )
966986 . map ( |f| ty:: FieldDef {
0 commit comments