@@ -2823,99 +2823,151 @@ pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool {
2823
2823
/// distinguish between types that are recursive with themselves and types that
2824
2824
/// contain a different recursive type. These cases can therefore be treated
2825
2825
/// differently when reporting errors.
2826
- #[ deriving( PartialEq ) ]
2826
+ ///
2827
+ /// The ordering of the cases is significant. They are sorted so that cmp::max
2828
+ /// will keep the "more erroneous" of two values.
2829
+ #[ deriving( PartialOrd , Ord , Eq , PartialEq , Show ) ]
2827
2830
pub enum Representability {
2828
2831
Representable ,
2829
- SelfRecursive ,
2830
2832
ContainsRecursive ,
2833
+ SelfRecursive ,
2831
2834
}
2832
2835
2833
2836
/// Check whether a type is representable. This means it cannot contain unboxed
2834
2837
/// structural recursion. This check is needed for structs and enums.
2835
2838
pub fn is_type_representable ( cx : & ctxt , sp : Span , ty : t ) -> Representability {
2836
2839
2837
2840
// Iterate until something non-representable is found
2838
- fn find_nonrepresentable < It : Iterator < t > > ( cx : & ctxt , sp : Span , seen : & mut Vec < DefId > ,
2841
+ fn find_nonrepresentable < It : Iterator < t > > ( cx : & ctxt , sp : Span , seen : & mut Vec < t > ,
2839
2842
mut iter : It ) -> Representability {
2840
- for ty in iter {
2841
- let r = type_structurally_recursive ( cx, sp, seen, ty) ;
2842
- if r != Representable {
2843
- return r
2844
- }
2845
- }
2846
- Representable
2843
+ iter. fold ( Representable ,
2844
+ |r, ty| cmp:: max ( r, is_type_structurally_recursive ( cx, sp, seen, ty) ) )
2847
2845
}
2848
2846
2849
- // Does the type `ty` directly (without indirection through a pointer)
2850
- // contain any types on stack `seen`?
2851
- fn type_structurally_recursive ( cx : & ctxt , sp : Span , seen : & mut Vec < DefId > ,
2852
- ty : t ) -> Representability {
2853
- debug ! ( "type_structurally_recursive: {}" ,
2854
- :: util:: ppaux:: ty_to_string( cx, ty) ) ;
2855
-
2856
- // Compare current type to previously seen types
2857
- match get ( ty) . sty {
2858
- ty_struct( did, _) |
2859
- ty_enum( did, _) => {
2860
- for ( i, & seen_did) in seen. iter ( ) . enumerate ( ) {
2861
- if did == seen_did {
2862
- return if i == 0 { SelfRecursive }
2863
- else { ContainsRecursive }
2864
- }
2865
- }
2866
- }
2867
- _ => ( ) ,
2868
- }
2869
-
2870
- // Check inner types
2847
+ fn are_inner_types_recursive ( cx : & ctxt , sp : Span ,
2848
+ seen : & mut Vec < t > , ty : t ) -> Representability {
2871
2849
match get ( ty) . sty {
2872
- // Tuples
2873
2850
ty_tup( ref ts) => {
2874
2851
find_nonrepresentable ( cx, sp, seen, ts. iter ( ) . map ( |t| * t) )
2875
2852
}
2876
2853
// Fixed-length vectors.
2877
2854
// FIXME(#11924) Behavior undecided for zero-length vectors.
2878
2855
ty_vec( ty, Some ( _) ) => {
2879
- type_structurally_recursive ( cx, sp, seen, ty)
2856
+ is_type_structurally_recursive ( cx, sp, seen, ty)
2880
2857
}
2881
-
2882
- // Push struct and enum def-ids onto `seen` before recursing.
2883
2858
ty_struct( did, ref substs) => {
2884
- seen. push ( did) ;
2885
2859
let fields = struct_fields ( cx, did, substs) ;
2886
- let r = find_nonrepresentable ( cx, sp, seen,
2887
- fields. iter ( ) . map ( |f| f. mt . ty ) ) ;
2888
- seen. pop ( ) ;
2889
- r
2860
+ find_nonrepresentable ( cx, sp, seen, fields. iter ( ) . map ( |f| f. mt . ty ) )
2890
2861
}
2891
-
2892
2862
ty_enum( did, ref substs) => {
2893
- seen. push ( did) ;
2894
2863
let vs = enum_variants ( cx, did) ;
2864
+ let iter = vs. iter ( )
2865
+ . flat_map ( |variant| { variant. args . iter ( ) } )
2866
+ . map ( |aty| { aty. subst_spanned ( cx, substs, Some ( sp) ) } ) ;
2895
2867
2896
- let mut r = Representable ;
2897
- for variant in vs. iter ( ) {
2898
- let iter = variant. args . iter ( ) . map ( |aty| {
2899
- aty. subst_spanned ( cx, substs, Some ( sp) )
2900
- } ) ;
2901
- r = find_nonrepresentable ( cx, sp, seen, iter) ;
2868
+ find_nonrepresentable ( cx, sp, seen, iter)
2869
+ }
2870
+ ty_unboxed_closure( did, _) => {
2871
+ let upvars = unboxed_closure_upvars ( cx, did) ;
2872
+ find_nonrepresentable ( cx, sp, seen, upvars. iter ( ) . map ( |f| f. ty ) )
2873
+ }
2874
+ _ => Representable ,
2875
+ }
2876
+ }
2902
2877
2903
- if r != Representable { break }
2878
+ fn same_struct_or_enum_def_id ( ty : t , did : DefId ) -> bool {
2879
+ match get ( ty) . sty {
2880
+ ty_struct( ty_did, _) | ty_enum( ty_did, _) => {
2881
+ ty_did == did
2882
+ }
2883
+ _ => false
2884
+ }
2885
+ }
2886
+
2887
+ fn same_type ( a : t , b : t ) -> bool {
2888
+ match ( & get ( a) . sty , & get ( b) . sty ) {
2889
+ ( & ty_struct( did_a, ref substs_a) , & ty_struct( did_b, ref substs_b) ) |
2890
+ ( & ty_enum( did_a, ref substs_a) , & ty_enum( did_b, ref substs_b) ) => {
2891
+ if did_a != did_b {
2892
+ return false ;
2904
2893
}
2905
2894
2906
- seen. pop ( ) ;
2907
- r
2908
- }
2895
+ let types_a = substs_a. types . get_slice ( subst:: TypeSpace ) ;
2896
+ let types_b = substs_b. types . get_slice ( subst:: TypeSpace ) ;
2909
2897
2910
- ty_unboxed_closure ( did , _ ) => {
2911
- let upvars = unboxed_closure_upvars ( cx , did ) ;
2912
- find_nonrepresentable ( cx ,
2913
- sp ,
2914
- seen ,
2915
- upvars . iter ( ) . map ( |f| f . ty ) )
2898
+ let mut pairs = types_a . iter ( ) . zip ( types_b . iter ( ) ) ;
2899
+
2900
+ pairs . all ( | ( & a , & b ) | same_type ( a , b ) )
2901
+ }
2902
+ _ => {
2903
+ type_id ( a ) == type_id ( b )
2916
2904
}
2905
+ }
2906
+ }
2917
2907
2918
- _ => Representable ,
2908
+ // Does the type `ty` directly (without indirection through a pointer)
2909
+ // contain any types on stack `seen`?
2910
+ fn is_type_structurally_recursive ( cx : & ctxt , sp : Span , seen : & mut Vec < t > ,
2911
+ ty : t ) -> Representability {
2912
+ debug ! ( "is_type_structurally_recursive: {}" ,
2913
+ :: util:: ppaux:: ty_to_string( cx, ty) ) ;
2914
+
2915
+ match get ( ty) . sty {
2916
+ ty_struct( did, _) | ty_enum( did, _) => {
2917
+ {
2918
+ // Iterate through stack of previously seen types.
2919
+ let mut iter = seen. iter ( ) ;
2920
+
2921
+ // The first item in `seen` is the type we are actually curious about.
2922
+ // We want to return SelfRecursive if this type contains itself.
2923
+ // It is important that we DON'T take generic parameters into account
2924
+ // for this check, so that Bar<T> in this example counts as SelfRecursive:
2925
+ //
2926
+ // struct Foo;
2927
+ // struct Bar<T> { x: Bar<Foo> }
2928
+
2929
+ match iter. next ( ) {
2930
+ Some ( & seen_type) => {
2931
+ if same_struct_or_enum_def_id ( seen_type, did) {
2932
+ debug ! ( "SelfRecursive: {} contains {}" ,
2933
+ :: util:: ppaux:: ty_to_string( cx, seen_type) ,
2934
+ :: util:: ppaux:: ty_to_string( cx, ty) ) ;
2935
+ return SelfRecursive ;
2936
+ }
2937
+ }
2938
+ None => { }
2939
+ }
2940
+
2941
+ // We also need to know whether the first item contains other types that
2942
+ // are structurally recursive. If we don't catch this case, we will recurse
2943
+ // infinitely for some inputs.
2944
+ //
2945
+ // It is important that we DO take generic parameters into account here,
2946
+ // so that code like this is considered SelfRecursive, not ContainsRecursive:
2947
+ //
2948
+ // struct Foo { Option<Option<Foo>> }
2949
+
2950
+ for & seen_type in iter {
2951
+ if same_type ( ty, seen_type) {
2952
+ debug ! ( "ContainsRecursive: {} contains {}" ,
2953
+ :: util:: ppaux:: ty_to_string( cx, seen_type) ,
2954
+ :: util:: ppaux:: ty_to_string( cx, ty) ) ;
2955
+ return ContainsRecursive ;
2956
+ }
2957
+ }
2958
+ }
2959
+
2960
+ // For structs and enums, track all previously seen types by pushing them
2961
+ // onto the 'seen' stack.
2962
+ seen. push ( ty) ;
2963
+ let out = are_inner_types_recursive ( cx, sp, seen, ty) ;
2964
+ seen. pop ( ) ;
2965
+ out
2966
+ }
2967
+ _ => {
2968
+ // No need to push in other cases.
2969
+ are_inner_types_recursive ( cx, sp, seen, ty)
2970
+ }
2919
2971
}
2920
2972
}
2921
2973
@@ -2925,8 +2977,11 @@ pub fn is_type_representable(cx: &ctxt, sp: Span, ty: t) -> Representability {
2925
2977
// To avoid a stack overflow when checking an enum variant or struct that
2926
2978
// contains a different, structurally recursive type, maintain a stack
2927
2979
// of seen types and check recursion for each of them (issues #3008, #3779).
2928
- let mut seen: Vec < DefId > = Vec :: new ( ) ;
2929
- type_structurally_recursive ( cx, sp, & mut seen, ty)
2980
+ let mut seen: Vec < t > = Vec :: new ( ) ;
2981
+ let r = is_type_structurally_recursive ( cx, sp, & mut seen, ty) ;
2982
+ debug ! ( "is_type_representable: {} is {}" ,
2983
+ :: util:: ppaux:: ty_to_string( cx, ty) , r) ;
2984
+ r
2930
2985
}
2931
2986
2932
2987
pub fn type_is_trait ( ty : t ) -> bool {
0 commit comments