@@ -2348,53 +2348,95 @@ pub fn is_instantiable(cx: ctxt, r_ty: t) -> bool {
2348
2348
!subtypes_require ( cx, & mut seen, r_ty, r_ty)
2349
2349
}
2350
2350
2351
- pub fn type_structurally_contains ( cx : ctxt , ty : t , test: |x: & sty | -> bool )
2352
- -> bool {
2353
- let sty = & get ( ty) . sty ;
2354
- debug ! ( "type_structurally_contains: {}" ,
2355
- :: util:: ppaux:: ty_to_str( cx, ty) ) ;
2356
- if test ( sty) { return true ; }
2357
- match * sty {
2358
- ty_enum( did, ref substs) => {
2359
- for variant in ( * enum_variants ( cx, did) ) . iter ( ) {
2360
- for aty in variant. args . iter ( ) {
2361
- let sty = subst ( cx, substs, * aty) ;
2362
- if type_structurally_contains ( cx, sty, |x| test ( x) ) { return true ; }
2351
+ // Needed to distinguish between types that are recursive with themselves,
2352
+ // and types that contain a different recursive type.
2353
+ #[ deriving( Eq ) ]
2354
+ pub enum Repr {
2355
+ Representable ,
2356
+ SelfRecursive ,
2357
+ ContainsRecursive ,
2358
+ }
2359
+
2360
+ // True if `ty` contains no structural recursion. This is necessary
2361
+ // for structs and enums to have finite size.
2362
+ pub fn is_type_representable ( cx : ctxt , ty : t ) -> Repr {
2363
+
2364
+ // Does the type `ty` directly (without indirection through a pointer)
2365
+ // contain any types on stack `seen`?
2366
+ fn type_structurally_recursive ( cx : ctxt , ty : t ,
2367
+ seen : & mut ~[ DefId ] ) -> Repr {
2368
+ debug ! ( "type_structurally_recursive: {}" ,
2369
+ :: util:: ppaux:: ty_to_str( cx, ty) ) ;
2370
+
2371
+ // Compare current type to previously seen types (stack 'seen')
2372
+ match get ( ty) . sty {
2373
+ ty_struct( did, _) |
2374
+ ty_enum( did, _) => {
2375
+ for ( i, & seen_did) in seen. iter ( ) . enumerate ( ) {
2376
+ if did == seen_did {
2377
+ return if i == 0 { SelfRecursive }
2378
+ else { ContainsRecursive }
2379
+ }
2380
+ }
2363
2381
}
2382
+ _ => ( ) ,
2364
2383
}
2365
- return false ;
2366
- }
2367
- ty_struct( did, ref substs) => {
2368
- let r = lookup_struct_fields ( cx, did) ;
2369
- for field in r. iter ( ) {
2370
- let ft = lookup_field_type ( cx, did, field. id , substs) ;
2371
- if type_structurally_contains ( cx, ft, |x| test ( x) ) { return true ; }
2372
- }
2373
- return false ;
2374
- }
2375
2384
2376
- ty_tup( ref ts) => {
2377
- for tt in ts. iter ( ) {
2378
- if type_structurally_contains ( cx, * tt, |x| test ( x) ) { return true ; }
2385
+ // Check inner types
2386
+ match get ( ty) . sty {
2387
+ // Tuples
2388
+ ty_tup( ref ts) => {
2389
+ let mut r = Representable ;
2390
+ for t in ts. iter ( ) {
2391
+ r = type_structurally_recursive ( cx, * t, seen) ;
2392
+ if r != Representable { break ; }
2393
+ }
2394
+ r
2395
+ }
2396
+ // Non-zero fixed-length vectors.
2397
+ ty_vec( mt, vstore_fixed( len) ) if len != 0 => {
2398
+ type_structurally_recursive ( cx, mt. ty , seen)
2399
+ }
2400
+
2401
+ // Push struct and enum def-ids/substs onto `seen` before recursing.
2402
+ ty_struct( did, ref substs) => {
2403
+ seen. push ( did) ;
2404
+ let fields = struct_fields ( cx, did, substs) ;
2405
+ let mut r = Representable ;
2406
+ for f in fields. iter ( ) {
2407
+ r = type_structurally_recursive ( cx, f. mt . ty , seen) ;
2408
+ if r != Representable { break ; }
2409
+ }
2410
+ seen. pop ( ) ;
2411
+ r
2412
+ }
2413
+ ty_enum( did, ref substs) => {
2414
+ seen. push ( did) ;
2415
+ let vs = enum_variants ( cx, did) ;
2416
+ let mut r = Representable ;
2417
+ ' outer: for variant in vs. iter ( ) {
2418
+ for aty in variant. args . iter ( ) {
2419
+ let sty = subst ( cx, substs, * aty) ;
2420
+ r = type_structurally_recursive ( cx, sty, seen) ;
2421
+ if r != Representable { break ' outer }
2422
+ }
2423
+ } ;
2424
+ seen. pop ( ) ;
2425
+ r
2426
+ }
2427
+
2428
+ _ => Representable ,
2379
2429
}
2380
- return false ;
2381
- }
2382
- ty_vec( ref mt, vstore_fixed( _) ) => {
2383
- return type_structurally_contains ( cx, mt. ty , test) ;
2384
- }
2385
- _ => return false
2386
2430
}
2387
- }
2388
2431
2389
- pub fn type_structurally_contains_uniques ( cx : ctxt , ty : t ) -> bool {
2390
- return type_structurally_contains ( cx, ty, |sty| {
2391
- match * sty {
2392
- ty_uniq( _) |
2393
- ty_vec( _, vstore_uniq) |
2394
- ty_str( vstore_uniq) => true ,
2395
- _ => false ,
2396
- }
2397
- } ) ;
2432
+ debug ! ( "is_type_representable: {}" ,
2433
+ :: util:: ppaux:: ty_to_str( cx, ty) ) ;
2434
+
2435
+ // To avoid a stack overflow when checking an enum with a variant that
2436
+ // that contains a different, structurally recursive type, maintain a
2437
+ // stack of seen types and check recursion for each of them (issue #3008).
2438
+ let mut seen: ~[ DefId ] = ~[ ] ;
2439
+ type_structurally_recursive ( cx, ty, & mut seen)
2398
2440
}
2399
2441
2400
2442
pub fn type_is_trait ( ty : t ) -> bool {
0 commit comments