@@ -2823,99 +2823,151 @@ pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool {
28232823/// distinguish between types that are recursive with themselves and types that
28242824/// contain a different recursive type. These cases can therefore be treated
28252825/// 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 ) ]
28272830pub enum Representability {
28282831 Representable ,
2829- SelfRecursive ,
28302832 ContainsRecursive ,
2833+ SelfRecursive ,
28312834}
28322835
28332836/// Check whether a type is representable. This means it cannot contain unboxed
28342837/// structural recursion. This check is needed for structs and enums.
28352838pub fn is_type_representable ( cx : & ctxt , sp : Span , ty : t ) -> Representability {
28362839
28372840 // 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 > ,
28392842 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) ) )
28472845 }
28482846
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 {
28712849 match get ( ty) . sty {
2872- // Tuples
28732850 ty_tup( ref ts) => {
28742851 find_nonrepresentable ( cx, sp, seen, ts. iter ( ) . map ( |t| * t) )
28752852 }
28762853 // Fixed-length vectors.
28772854 // FIXME(#11924) Behavior undecided for zero-length vectors.
28782855 ty_vec( ty, Some ( _) ) => {
2879- type_structurally_recursive ( cx, sp, seen, ty)
2856+ is_type_structurally_recursive ( cx, sp, seen, ty)
28802857 }
2881-
2882- // Push struct and enum def-ids onto `seen` before recursing.
28832858 ty_struct( did, ref substs) => {
2884- seen. push ( did) ;
28852859 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 ) )
28902861 }
2891-
28922862 ty_enum( did, ref substs) => {
2893- seen. push ( did) ;
28942863 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) ) } ) ;
28952867
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+ }
29022877
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 ;
29042893 }
29052894
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 ) ;
29092897
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 )
29162904 }
2905+ }
2906+ }
29172907
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+ }
29192971 }
29202972 }
29212973
@@ -2925,8 +2977,11 @@ pub fn is_type_representable(cx: &ctxt, sp: Span, ty: t) -> Representability {
29252977 // To avoid a stack overflow when checking an enum variant or struct that
29262978 // contains a different, structurally recursive type, maintain a stack
29272979 // 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
29302985}
29312986
29322987pub fn type_is_trait ( ty : t ) -> bool {
0 commit comments