@@ -781,64 +781,100 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
781781 }
782782}
783783
784- /*
785- /// In a type definition, we check that unnamed field names are distinct.
786- fn check_unnamed_fields_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>) {
787- let mut seen_fields: FxHashMap<Ident, Option<Span>> = Default::default();
788- fn check_fields_anon_adt_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, seen_fields: &mut FxHashMap<Ident, Option<Span>>) {
789- let fields = match &item.kind {
790- hir::ItemKind::Struct(fields, _) | hir::ItemKind::Union(fields, _) => fields,
791- _ => return,
792- };
793- for field in fields.fields() {
794- if field.ident.name == kw::Underscore {
795- if let hir::TyKind::AnonAdt(item_id) = field.ty.kind() {
796- let item = tcx.hir().item(item_id);
797- check_fields_anon_adt_defn(tcx, item, &mut *seen_fields);
798- } else {
799- let field_ty = match tcx.type_of(field.def_id).instantiate_identity().ty_adt_def() {
800- Some(adt_ty) => adt_ty,
801- None => {
802- tcx.sess.emit_err(err);
803- return;
804- }
805- };
806- if let Some(def_id) = field_ty.did().as_local() {
807- let item = tcx.hir().item(hir::ItemId { owner_id: hir::OwnerId { def_id }});
808- check_fields_anon_adt_defn(tcx, item, &mut *seen_fields);
809- }
784+ #[ derive( Clone , Copy ) ]
785+ struct NestedSpan {
786+ span : Span ,
787+ nested_field_span : Span ,
788+ }
789+
790+ #[ derive( Clone , Copy ) ]
791+ enum FieldDeclSpan {
792+ NotNested ( Span ) ,
793+ Nested ( NestedSpan ) ,
794+ }
795+
796+ impl From < Span > for FieldDeclSpan {
797+ fn from ( span : Span ) -> Self {
798+ Self :: NotNested ( span)
799+ }
800+ }
801+
802+ impl From < NestedSpan > for FieldDeclSpan {
803+ fn from ( span : NestedSpan ) -> Self {
804+ Self :: Nested ( span)
805+ }
806+ }
807+
808+ /// Check the uniqueness of fields across adt where there are
809+ /// nested fields imported from an unnamed field.
810+ fn check_field_uniqueness_in_nested_adt (
811+ tcx : TyCtxt < ' _ > ,
812+ adt_def : ty:: AdtDef < ' _ > ,
813+ check : & mut impl FnMut ( Ident , /* nested_field_span */ Span ) ,
814+ ) {
815+ for field in adt_def. all_fields ( ) {
816+ if field. is_unnamed ( ) {
817+ // Here we don't care about the generic parameters, so `instantiate_identity` is enough.
818+ match tcx. type_of ( field. did ) . instantiate_identity ( ) . kind ( ) {
819+ ty:: Adt ( adt_def, _) => {
820+ check_field_uniqueness_in_nested_adt ( tcx, * adt_def, & mut * check) ;
810821 }
811- field_ty.flags()
812- let inner_adt_def = field_ty.ty_adt_def().expect("expect an adt");
813- check_fields_anon_adt_defn(tcx, adt_def, &mut *seen_fields);
814- } else {
815- let span = field.did.as_local().map(|did| {
816- let hir_id = tcx.hir().local_def_id_to_hir_id(did);
817- tcx.hir().span(hir_id)
818- });
819- match seen_fields.get(&ident.normalize_to_macros_2_0()).cloned() {
820- Some(Some(prev_span)) => {
821- tcx.sess.emit_err(errors::FieldAlreadyDeclared {
822- field_name: ident,
823- span: f.span,
824- prev_span,
825- });
826- }
827- Some(None) => {
828- tcx.sess.emit_err(errors::FieldAlreadyDeclared {
829- field_name: f.ident,
830- span: f.span,
831- prev_span,
832- });
822+ ty_kind => bug ! (
823+ "Unexpected ty kind in check_field_uniqueness_in_nested_adt(): {ty_kind:?}"
824+ ) ,
825+ }
826+ } else {
827+ check ( field. ident ( tcx) , tcx. def_span ( field. did ) ) ;
828+ }
829+ }
830+ }
831+
832+ /// Check the uniqueness of fields in a struct variant, and recursively
833+ /// check the nested fields if it is an unnamed field with type of an
834+ /// annoymous adt.
835+ fn check_field_uniqueness (
836+ tcx : TyCtxt < ' _ > ,
837+ field : & hir:: FieldDef < ' _ > ,
838+ check : & mut impl FnMut ( Ident , FieldDeclSpan ) ,
839+ ) {
840+ if field. ident . name == kw:: Underscore {
841+ let ty_span = field. ty . span ;
842+ match & field. ty . kind {
843+ hir:: TyKind :: AnonAdt ( item_id) => {
844+ match & tcx. hir_node ( item_id. hir_id ( ) ) . expect_item ( ) . kind {
845+ hir:: ItemKind :: Struct ( variant_data, ..)
846+ | hir:: ItemKind :: Union ( variant_data, ..) => {
847+ variant_data
848+ . fields ( )
849+ . iter ( )
850+ . for_each ( |f| check_field_uniqueness ( tcx, f, & mut * check) ) ;
833851 }
834- None =>
835- seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span);
852+ item_kind => span_bug ! (
853+ ty_span,
854+ "Unexpected item kind in check_field_uniqueness(): {item_kind:?}"
855+ ) ,
836856 }
837857 }
858+ hir:: TyKind :: Path ( hir:: QPath :: Resolved ( _, hir:: Path { res, .. } ) ) => {
859+ check_field_uniqueness_in_nested_adt (
860+ tcx,
861+ tcx. adt_def ( res. def_id ( ) ) ,
862+ & mut |ident, nested_field_span| {
863+ check ( ident, NestedSpan { span : field. span , nested_field_span } . into ( ) )
864+ } ,
865+ ) ;
866+ }
867+ // Abort due to errors (there must be an error if an unnamed field
868+ // has any type kind other than an anonymous adt or a named adt)
869+ _ => {
870+ debug_assert ! ( tcx. sess. has_errors( ) . is_some( ) ) ;
871+ tcx. sess . abort_if_errors ( )
872+ }
838873 }
874+ return ;
839875 }
876+ check ( field. ident , field. span . into ( ) ) ;
840877}
841- */
842878
843879fn convert_variant (
844880 tcx : TyCtxt < ' _ > ,
@@ -848,27 +884,61 @@ fn convert_variant(
848884 def : & hir:: VariantData < ' _ > ,
849885 adt_kind : ty:: AdtKind ,
850886 parent_did : LocalDefId ,
887+ is_anonymous : bool ,
851888) -> ty:: VariantDef {
852889 let mut has_unnamed_fields = false ;
853- let mut seen_fields: FxHashMap < Ident , Span > = Default :: default ( ) ;
890+ let mut seen_fields: FxHashMap < Ident , FieldDeclSpan > = Default :: default ( ) ;
854891 let fields = def
855892 . fields ( )
856893 . iter ( )
857894 . inspect ( |f| {
858- // Skip the unnamed field here, we will check it later.
859- if f. ident . name == kw:: Underscore {
860- has_unnamed_fields = true ;
861- return ;
862- }
863- let dup_span = seen_fields. get ( & f. ident . normalize_to_macros_2_0 ( ) ) . cloned ( ) ;
864- if let Some ( prev_span) = dup_span {
865- tcx. dcx ( ) . emit_err ( errors:: FieldAlreadyDeclared {
866- field_name : f. ident ,
867- span : f. span ,
868- prev_span,
895+ has_unnamed_fields |= f. ident . name == kw:: Underscore ;
896+ if !is_anonymous {
897+ check_field_uniqueness ( tcx, f, & mut |ident, field_decl| {
898+ use FieldDeclSpan :: * ;
899+ let field_name = ident. name ;
900+ let ident = ident. normalize_to_macros_2_0 ( ) ;
901+ match ( field_decl, seen_fields. get ( & ident) . copied ( ) ) {
902+ ( NotNested ( span) , Some ( NotNested ( prev_span) ) ) => {
903+ tcx. sess . emit_err ( errors:: FieldAlreadyDeclared :: NotNested {
904+ field_name,
905+ span,
906+ prev_span,
907+ } ) ;
908+ }
909+ ( NotNested ( span) , Some ( Nested ( prev) ) ) => {
910+ tcx. sess . emit_err ( errors:: FieldAlreadyDeclared :: PreviousNested {
911+ field_name,
912+ span,
913+ prev_span : prev. span ,
914+ prev_nested_field_span : prev. nested_field_span ,
915+ } ) ;
916+ }
917+ (
918+ Nested ( NestedSpan { span, nested_field_span } ) ,
919+ Some ( NotNested ( prev_span) ) ,
920+ ) => {
921+ tcx. sess . emit_err ( errors:: FieldAlreadyDeclared :: CurrentNested {
922+ field_name,
923+ span,
924+ nested_field_span,
925+ prev_span,
926+ } ) ;
927+ }
928+ ( Nested ( NestedSpan { span, nested_field_span } ) , Some ( Nested ( prev) ) ) => {
929+ tcx. sess . emit_err ( errors:: FieldAlreadyDeclared :: BothNested {
930+ field_name,
931+ span,
932+ nested_field_span,
933+ prev_span : prev. span ,
934+ prev_nested_field_span : prev. nested_field_span ,
935+ } ) ;
936+ }
937+ ( field_decl, None ) => {
938+ seen_fields. insert ( ident, field_decl) ;
939+ }
940+ }
869941 } ) ;
870- } else {
871- seen_fields. insert ( f. ident . normalize_to_macros_2_0 ( ) , f. span ) ;
872942 }
873943 } )
874944 . map ( |f| ty:: FieldDef {
@@ -929,6 +999,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
929999 & v. data ,
9301000 AdtKind :: Enum ,
9311001 def_id,
1002+ is_anonymous,
9321003 )
9331004 } )
9341005 . collect ( ) ;
@@ -948,6 +1019,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
9481019 def,
9491020 adt_kind,
9501021 def_id,
1022+ is_anonymous,
9511023 ) )
9521024 . collect ( ) ;
9531025
0 commit comments