@@ -789,64 +789,100 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
789789 }
790790}
791791
792- /*
793- /// In a type definition, we check that unnamed field names are distinct.
794- fn check_unnamed_fields_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>) {
795- let mut seen_fields: FxHashMap<Ident, Option<Span>> = Default::default();
796- fn check_fields_anon_adt_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, seen_fields: &mut FxHashMap<Ident, Option<Span>>) {
797- let fields = match &item.kind {
798- hir::ItemKind::Struct(fields, _) | hir::ItemKind::Union(fields, _) => fields,
799- _ => return,
800- };
801- for field in fields.fields() {
802- if field.ident.name == kw::Underscore {
803- if let hir::TyKind::AnonAdt(item_id) = field.ty.kind() {
804- let item = tcx.hir().item(item_id);
805- check_fields_anon_adt_defn(tcx, item, &mut *seen_fields);
806- } else {
807- let field_ty = match tcx.type_of(field.def_id).instantiate_identity().ty_adt_def() {
808- Some(adt_ty) => adt_ty,
809- None => {
810- tcx.sess.emit_err(err);
811- return;
812- }
813- };
814- if let Some(def_id) = field_ty.did().as_local() {
815- let item = tcx.hir().item(hir::ItemId { owner_id: hir::OwnerId { def_id }});
816- check_fields_anon_adt_defn(tcx, item, &mut *seen_fields);
817- }
792+ #[ derive( Clone , Copy ) ]
793+ struct NestedSpan {
794+ span : Span ,
795+ nested_field_span : Span ,
796+ }
797+
798+ #[ derive( Clone , Copy ) ]
799+ enum FieldDeclSpan {
800+ NotNested ( Span ) ,
801+ Nested ( NestedSpan ) ,
802+ }
803+
804+ impl From < Span > for FieldDeclSpan {
805+ fn from ( span : Span ) -> Self {
806+ Self :: NotNested ( span)
807+ }
808+ }
809+
810+ impl From < NestedSpan > for FieldDeclSpan {
811+ fn from ( span : NestedSpan ) -> Self {
812+ Self :: Nested ( span)
813+ }
814+ }
815+
816+ /// Check the uniqueness of fields across adt where there are
817+ /// nested fields imported from an unnamed field.
818+ fn check_field_uniqueness_in_nested_adt (
819+ tcx : TyCtxt < ' _ > ,
820+ adt_def : ty:: AdtDef < ' _ > ,
821+ check : & mut impl FnMut ( Ident , /* nested_field_span */ Span ) ,
822+ ) {
823+ for field in adt_def. all_fields ( ) {
824+ if field. is_unnamed ( ) {
825+ // Here we don't care about the generic parameters, so `instantiate_identity` is enough.
826+ match tcx. type_of ( field. did ) . instantiate_identity ( ) . kind ( ) {
827+ ty:: Adt ( adt_def, _) => {
828+ check_field_uniqueness_in_nested_adt ( tcx, * adt_def, & mut * check) ;
818829 }
819- field_ty.flags()
820- let inner_adt_def = field_ty.ty_adt_def().expect("expect an adt");
821- check_fields_anon_adt_defn(tcx, adt_def, &mut *seen_fields);
822- } else {
823- let span = field.did.as_local().map(|did| {
824- let hir_id = tcx.hir().local_def_id_to_hir_id(did);
825- tcx.hir().span(hir_id)
826- });
827- match seen_fields.get(&ident.normalize_to_macros_2_0()).cloned() {
828- Some(Some(prev_span)) => {
829- tcx.sess.emit_err(errors::FieldAlreadyDeclared {
830- field_name: ident,
831- span: f.span,
832- prev_span,
833- });
834- }
835- Some(None) => {
836- tcx.sess.emit_err(errors::FieldAlreadyDeclared {
837- field_name: f.ident,
838- span: f.span,
839- prev_span,
840- });
830+ ty_kind => bug ! (
831+ "Unexpected ty kind in check_field_uniqueness_in_nested_adt(): {ty_kind:?}"
832+ ) ,
833+ }
834+ } else {
835+ check ( field. ident ( tcx) , tcx. def_span ( field. did ) ) ;
836+ }
837+ }
838+ }
839+
840+ /// Check the uniqueness of fields in a struct variant, and recursively
841+ /// check the nested fields if it is an unnamed field with type of an
842+ /// annoymous adt.
843+ fn check_field_uniqueness (
844+ tcx : TyCtxt < ' _ > ,
845+ field : & hir:: FieldDef < ' _ > ,
846+ check : & mut impl FnMut ( Ident , FieldDeclSpan ) ,
847+ ) {
848+ if field. ident . name == kw:: Underscore {
849+ let ty_span = field. ty . span ;
850+ match & field. ty . kind {
851+ hir:: TyKind :: AnonAdt ( item_id) => {
852+ match & tcx. hir_node ( item_id. hir_id ( ) ) . expect_item ( ) . kind {
853+ hir:: ItemKind :: Struct ( variant_data, ..)
854+ | hir:: ItemKind :: Union ( variant_data, ..) => {
855+ variant_data
856+ . fields ( )
857+ . iter ( )
858+ . for_each ( |f| check_field_uniqueness ( tcx, f, & mut * check) ) ;
841859 }
842- None =>
843- seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span);
860+ item_kind => span_bug ! (
861+ ty_span,
862+ "Unexpected item kind in check_field_uniqueness(): {item_kind:?}"
863+ ) ,
844864 }
845865 }
866+ hir:: TyKind :: Path ( hir:: QPath :: Resolved ( _, hir:: Path { res, .. } ) ) => {
867+ check_field_uniqueness_in_nested_adt (
868+ tcx,
869+ tcx. adt_def ( res. def_id ( ) ) ,
870+ & mut |ident, nested_field_span| {
871+ check ( ident, NestedSpan { span : field. span , nested_field_span } . into ( ) )
872+ } ,
873+ ) ;
874+ }
875+ // Abort due to errors (there must be an error if an unnamed field
876+ // has any type kind other than an anonymous adt or a named adt)
877+ _ => {
878+ debug_assert ! ( tcx. sess. has_errors( ) . is_some( ) ) ;
879+ tcx. sess . abort_if_errors ( )
880+ }
846881 }
882+ return ;
847883 }
884+ check ( field. ident , field. span . into ( ) ) ;
848885}
849- */
850886
851887fn convert_variant (
852888 tcx : TyCtxt < ' _ > ,
@@ -856,27 +892,61 @@ fn convert_variant(
856892 def : & hir:: VariantData < ' _ > ,
857893 adt_kind : ty:: AdtKind ,
858894 parent_did : LocalDefId ,
895+ is_anonymous : bool ,
859896) -> ty:: VariantDef {
860897 let mut has_unnamed_fields = false ;
861- let mut seen_fields: FxHashMap < Ident , Span > = Default :: default ( ) ;
898+ let mut seen_fields: FxHashMap < Ident , FieldDeclSpan > = Default :: default ( ) ;
862899 let fields = def
863900 . fields ( )
864901 . iter ( )
865902 . inspect ( |f| {
866- // Skip the unnamed field here, we will check it later.
867- if f. ident . name == kw:: Underscore {
868- has_unnamed_fields = true ;
869- return ;
870- }
871- let dup_span = seen_fields. get ( & f. ident . normalize_to_macros_2_0 ( ) ) . cloned ( ) ;
872- if let Some ( prev_span) = dup_span {
873- tcx. dcx ( ) . emit_err ( errors:: FieldAlreadyDeclared {
874- field_name : f. ident ,
875- span : f. span ,
876- prev_span,
903+ has_unnamed_fields |= f. ident . name == kw:: Underscore ;
904+ if !is_anonymous {
905+ check_field_uniqueness ( tcx, f, & mut |ident, field_decl| {
906+ use FieldDeclSpan :: * ;
907+ let field_name = ident. name ;
908+ let ident = ident. normalize_to_macros_2_0 ( ) ;
909+ match ( field_decl, seen_fields. get ( & ident) . copied ( ) ) {
910+ ( NotNested ( span) , Some ( NotNested ( prev_span) ) ) => {
911+ tcx. sess . emit_err ( errors:: FieldAlreadyDeclared :: NotNested {
912+ field_name,
913+ span,
914+ prev_span,
915+ } ) ;
916+ }
917+ ( NotNested ( span) , Some ( Nested ( prev) ) ) => {
918+ tcx. sess . emit_err ( errors:: FieldAlreadyDeclared :: PreviousNested {
919+ field_name,
920+ span,
921+ prev_span : prev. span ,
922+ prev_nested_field_span : prev. nested_field_span ,
923+ } ) ;
924+ }
925+ (
926+ Nested ( NestedSpan { span, nested_field_span } ) ,
927+ Some ( NotNested ( prev_span) ) ,
928+ ) => {
929+ tcx. sess . emit_err ( errors:: FieldAlreadyDeclared :: CurrentNested {
930+ field_name,
931+ span,
932+ nested_field_span,
933+ prev_span,
934+ } ) ;
935+ }
936+ ( Nested ( NestedSpan { span, nested_field_span } ) , Some ( Nested ( prev) ) ) => {
937+ tcx. sess . emit_err ( errors:: FieldAlreadyDeclared :: BothNested {
938+ field_name,
939+ span,
940+ nested_field_span,
941+ prev_span : prev. span ,
942+ prev_nested_field_span : prev. nested_field_span ,
943+ } ) ;
944+ }
945+ ( field_decl, None ) => {
946+ seen_fields. insert ( ident, field_decl) ;
947+ }
948+ }
877949 } ) ;
878- } else {
879- seen_fields. insert ( f. ident . normalize_to_macros_2_0 ( ) , f. span ) ;
880950 }
881951 } )
882952 . map ( |f| ty:: FieldDef {
@@ -937,6 +1007,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
9371007 & v. data ,
9381008 AdtKind :: Enum ,
9391009 def_id,
1010+ is_anonymous,
9401011 )
9411012 } )
9421013 . collect ( ) ;
@@ -956,6 +1027,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
9561027 def,
9571028 adt_kind,
9581029 def_id,
1030+ is_anonymous,
9591031 ) )
9601032 . collect ( ) ;
9611033
0 commit comments