@@ -781,64 +781,100 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
781
781
}
782
782
}
783
783
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) ;
810
821
}
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) ) ;
833
851
}
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
+ ) ,
836
856
}
837
857
}
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
+ }
838
873
}
874
+ return ;
839
875
}
876
+ check ( field. ident , field. span . into ( ) ) ;
840
877
}
841
- */
842
878
843
879
fn convert_variant (
844
880
tcx : TyCtxt < ' _ > ,
@@ -848,27 +884,61 @@ fn convert_variant(
848
884
def : & hir:: VariantData < ' _ > ,
849
885
adt_kind : ty:: AdtKind ,
850
886
parent_did : LocalDefId ,
887
+ is_anonymous : bool ,
851
888
) -> ty:: VariantDef {
852
889
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 ( ) ;
854
891
let fields = def
855
892
. fields ( )
856
893
. iter ( )
857
894
. 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
+ }
869
941
} ) ;
870
- } else {
871
- seen_fields. insert ( f. ident . normalize_to_macros_2_0 ( ) , f. span ) ;
872
942
}
873
943
} )
874
944
. map ( |f| ty:: FieldDef {
@@ -929,6 +999,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
929
999
& v. data ,
930
1000
AdtKind :: Enum ,
931
1001
def_id,
1002
+ is_anonymous,
932
1003
)
933
1004
} )
934
1005
. collect ( ) ;
@@ -948,6 +1019,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
948
1019
def,
949
1020
adt_kind,
950
1021
def_id,
1022
+ is_anonymous,
951
1023
) )
952
1024
. collect ( ) ;
953
1025
0 commit comments