@@ -778,19 +778,53 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
778
778
}
779
779
}
780
780
781
+ /// Get the `DefId` for a given struct or enum `Ty`.
782
+ fn ty_def_id ( ty : & hir:: Ty ) -> Option < DefId > {
783
+ match ty. node {
784
+ hir:: TyPath ( hir:: QPath :: Resolved ( _, ref path) ) => {
785
+ match path. def {
786
+ hir:: def:: Def :: Struct ( did) | hir:: def:: Def :: Enum ( did) => {
787
+ Some ( did)
788
+ }
789
+ _ => None ,
790
+ }
791
+ } ,
792
+ _ => None ,
793
+ }
794
+ }
795
+
781
796
impl < ' a , ' gcx , ' tcx > TyCtxt < ' a , ' gcx , ' tcx > {
782
- fn foo ( & self , id : ast:: NodeId , ty : & hir:: Ty , sp : Span , err : & mut DiagnosticBuilder < ' tcx > ) -> bool {
783
- if let Some ( Node :: NodeItem ( item) ) = ty. ty_def_id ( ) . and_then ( |id| {
784
- self . hir . get_if_local ( id)
785
- } ) {
786
- if self . is_node_id_referenced_in_item ( item, id) {
787
- err. span_label ( sp, & "recursive here" ) ;
797
+ /// Add a span label to `err` pointing at `sp` if the field represented by `node_id` points
798
+ /// recursively at the type `ty` without indirection.
799
+ fn annotate_recursive_field_ty ( & self ,
800
+ node_id : ast:: NodeId ,
801
+ ty : & hir:: Ty ,
802
+ sp : Span ,
803
+ err : & mut DiagnosticBuilder < ' tcx > ) -> bool {
804
+ if let Some ( did) = ty_def_id ( ty) {
805
+ return self . annotate_recursive_field_id ( node_id, did, sp, err) ;
806
+ }
807
+ false
808
+ }
809
+
810
+ /// Add a span label to `err` pointing at `sp` if the field represented by `node_id` points
811
+ /// recursively at the type represented by `did` without indirection.
812
+ fn annotate_recursive_field_id ( & self ,
813
+ node_id :
814
+ ast:: NodeId ,
815
+ did : DefId ,
816
+ sp : Span ,
817
+ err : & mut DiagnosticBuilder < ' tcx > ) -> bool
818
+ {
819
+ if let Some ( Node :: NodeItem ( item) ) = self . hir . get_if_local ( did) {
820
+ if self . is_node_id_referenced_in_item ( item, node_id) {
821
+ err. span_label ( sp, & "recursive without indirection" ) ;
822
+ return true ;
788
823
}
789
- true
790
- } else {
791
- false
792
824
}
825
+ false
793
826
}
827
+
794
828
pub fn recursive_type_with_infinite_size_error ( self ,
795
829
type_def_id : DefId )
796
830
-> DiagnosticBuilder < ' tcx >
@@ -806,114 +840,62 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
806
840
at some point to make `{}` representable",
807
841
self . item_path_str( type_def_id) ) ) ;
808
842
843
+ // Look at the type for the the recursive type's fields and label those that are causing it
844
+ // to be of infinite size.
809
845
if let Some ( Node :: NodeItem ( self_item) ) = self . hir . get_if_local ( type_def_id) {
810
- match self_item. node {
811
- hir:: ItemStruct ( hir:: VariantData :: Struct ( ref fields, _) , _) |
812
- hir:: ItemStruct ( hir:: VariantData :: Tuple ( ref fields, _) , _) => {
813
- for field in fields {
814
- match field. ty . node {
815
- hir:: TyPath ( ref qpath) => {
816
- // Foo | Option<Foo>
817
- if let & hir:: QPath :: Resolved ( _, ref path) = qpath {
818
- for segment in path. segments . iter ( ) {
819
- if let hir:: AngleBracketedParameters (
820
- hir:: AngleBracketedParameterData {
821
- ref types, ..
822
- } ) = segment. parameters
823
- {
824
- for ty in types {
825
- if self . foo ( self_item. id , & ty, field. span ,
826
- & mut err) {
827
- break ;
828
- }
829
- }
830
- }
831
-
832
- }
833
- match path. def {
834
- hir:: def:: Def :: Struct ( did) | hir:: def:: Def :: Enum ( did) => {
835
- let local = self . hir . get_if_local ( did) ;
836
- if let Some ( Node :: NodeItem ( item) ) = local {
837
- if self . is_node_id_referenced_in_item ( item,
838
- self_item. id )
839
- {
840
- err. span_label ( field. span , & "recursive here" ) ;
841
- }
842
- }
843
- }
844
- _ => ( ) ,
845
- }
846
+ for field in self_item. node . fields ( ) {
847
+ match field. ty . node {
848
+ hir:: TyPath ( ref qpath) => {
849
+ // Foo
850
+ if let & hir:: QPath :: Resolved ( _, ref path) = qpath {
851
+ match path. def {
852
+ hir:: def:: Def :: Struct ( did) |
853
+ hir:: def:: Def :: Enum ( did) => {
854
+ self . annotate_recursive_field_id ( self_item. id ,
855
+ did,
856
+ field. span ,
857
+ & mut err) ;
846
858
}
859
+ _ => ( ) ,
847
860
}
848
- hir:: TySlice ( ref ty) |
849
- hir:: TyArray ( ref ty, _) |
850
- hir:: TyPtr ( hir:: MutTy { ref ty, .. } ) |
851
- hir:: TyRptr ( _, hir:: MutTy { ref ty, .. } ) => {
852
- // &[Foo] | [Foo] | &'a [Foo]
853
- if let hir:: TySlice ( ref ty) = ty. node {
854
- // &'a [Foo]
855
- let _ = self . foo ( self_item. id , & ty, field. span , & mut err) ;
856
- } else {
857
- let _ = self . foo ( self_item. id , & ty, field. span , & mut err) ;
858
- }
859
- }
860
- hir:: TyTup ( ref tys) => {
861
- // (Foo, Bar)
862
- for ty in tys {
863
- if self . foo ( self_item. id , & ty, field. span , & mut err) {
864
- break ;
865
- }
866
- }
861
+ }
862
+ }
863
+ hir:: TyArray ( ref ty, _) => {
864
+ // [Foo]
865
+ self . annotate_recursive_field_ty ( self_item. id , & ty, field. span , & mut err) ;
866
+ }
867
+ hir:: TyTup ( ref tys) => {
868
+ // (Foo, Bar)
869
+ for ty in tys {
870
+ if self . annotate_recursive_field_ty ( self_item. id ,
871
+ & ty,
872
+ field. span ,
873
+ & mut err) {
874
+ break ;
867
875
}
868
- _ => ( ) ,
869
876
}
870
877
}
878
+ _ => ( ) ,
871
879
}
872
- _ => ( ) ,
873
880
}
874
881
}
875
882
err
876
883
}
877
884
885
+ /// Given `item`, determine wether the node identified by `node_id` is referenced without any
886
+ /// indirection in any of `item`'s fields.
878
887
fn is_node_id_referenced_in_item ( & self , item : & hir:: Item , node_id : ast:: NodeId ) -> bool {
879
888
if item. id == node_id {
880
889
return true ;
881
890
}
882
- match item. node {
883
- hir:: ItemStruct ( hir:: VariantData :: Struct ( ref fields, _) , _) |
884
- hir:: ItemStruct ( hir:: VariantData :: Tuple ( ref fields, _) , _) => {
885
- for field in fields {
886
- if let Some ( Node :: NodeItem ( ref item) ) = field. ty . ty_def_id ( ) . and_then ( |id| {
887
- self . hir . get_if_local ( id)
888
- } ) {
889
- if self . is_node_id_referenced_in_item ( item, node_id) {
890
- return true ;
891
- }
892
- }
893
- }
894
- }
895
- hir:: ItemEnum ( hir:: EnumDef { ref variants } , _) => {
896
- for variant in variants {
897
- match variant. node . data {
898
- hir:: VariantData :: Struct ( ref fields, _) |
899
- hir:: VariantData :: Tuple ( ref fields, _) => {
900
- for field in fields {
901
- if let Some ( Node :: NodeItem ( ref item) ) = field. ty
902
- . ty_def_id ( ) . and_then ( |id| {
903
- self . hir . get_if_local ( id)
904
- } )
905
- {
906
- if self . is_node_id_referenced_in_item ( item, node_id) {
907
- return true ;
908
- }
909
- }
910
- }
911
- }
912
- _ => ( ) ,
913
- }
891
+ for field in item. node . fields ( ) {
892
+ if let Some ( Node :: NodeItem ( ref item) ) = ty_def_id ( & field. ty ) . and_then ( |id| {
893
+ self . hir . get_if_local ( id)
894
+ } ) {
895
+ if self . is_node_id_referenced_in_item ( item, node_id) {
896
+ return true ;
914
897
}
915
898
}
916
- _ => ( ) ,
917
899
}
918
900
false
919
901
}
0 commit comments