@@ -2348,53 +2348,103 @@ 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
+ /// Describes whether a type is representable. For types that are not
2352
+ /// representable, 'SelfRecursive' and 'ContainsRecursive' are used to
2353
+ /// distinguish between types that are recursive with themselves and types that
2354
+ /// contain a different recursive type. These cases can therefore be treated
2355
+ /// differently when reporting errors.
2356
+ #[ deriving( Eq ) ]
2357
+ pub enum Representability {
2358
+ Representable ,
2359
+ SelfRecursive ,
2360
+ ContainsRecursive ,
2361
+ }
2362
+
2363
+ /// Check whether a type is representable. This means it cannot contain unboxed
2364
+ /// structural recursion. This check is needed for structs and enums.
2365
+ pub fn is_type_representable ( cx : ctxt , ty : t ) -> Representability {
2366
+
2367
+ // Iterate until something non-representable is found
2368
+ fn find_nonrepresentable < It : Iterator < t > > ( cx : ctxt , seen : & mut ~[ DefId ] ,
2369
+ mut iter : It ) -> Representability {
2370
+ for ty in iter {
2371
+ let r = type_structurally_recursive ( cx, seen, ty) ;
2372
+ if r != Representable {
2373
+ return r
2363
2374
}
2364
2375
}
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 ; }
2376
+ Representable
2377
+ }
2378
+
2379
+ // Does the type `ty` directly (without indirection through a pointer)
2380
+ // contain any types on stack `seen`?
2381
+ fn type_structurally_recursive ( cx : ctxt , seen : & mut ~[ DefId ] ,
2382
+ ty : t ) -> Representability {
2383
+ debug ! ( "type_structurally_recursive: {}" ,
2384
+ :: util:: ppaux:: ty_to_str( cx, ty) ) ;
2385
+
2386
+ // Compare current type to previously seen types
2387
+ match get ( ty) . sty {
2388
+ ty_struct( did, _) |
2389
+ ty_enum( did, _) => {
2390
+ for ( i, & seen_did) in seen. iter ( ) . enumerate ( ) {
2391
+ if did == seen_did {
2392
+ return if i == 0 { SelfRecursive }
2393
+ else { ContainsRecursive }
2394
+ }
2395
+ }
2396
+ }
2397
+ _ => ( ) ,
2372
2398
}
2373
- return false ;
2374
- }
2375
2399
2376
- ty_tup( ref ts) => {
2377
- for tt in ts. iter ( ) {
2378
- if type_structurally_contains ( cx, * tt, |x| test ( x) ) { return true ; }
2400
+ // Check inner types
2401
+ match get ( ty) . sty {
2402
+ // Tuples
2403
+ ty_tup( ref ts) => {
2404
+ find_nonrepresentable ( cx, seen, ts. iter ( ) . map ( |t| * t) )
2405
+ }
2406
+ // Non-zero fixed-length vectors.
2407
+ ty_vec( mt, vstore_fixed( len) ) if len != 0 => {
2408
+ type_structurally_recursive ( cx, seen, mt. ty )
2409
+ }
2410
+
2411
+ // Push struct and enum def-ids onto `seen` before recursing.
2412
+ ty_struct( did, ref substs) => {
2413
+ seen. push ( did) ;
2414
+ let fields = struct_fields ( cx, did, substs) ;
2415
+ let r = find_nonrepresentable ( cx, seen,
2416
+ fields. iter ( ) . map ( |f| f. mt . ty ) ) ;
2417
+ seen. pop ( ) ;
2418
+ r
2419
+ }
2420
+ ty_enum( did, ref substs) => {
2421
+ seen. push ( did) ;
2422
+ let vs = enum_variants ( cx, did) ;
2423
+
2424
+ let mut r = Representable ;
2425
+ for variant in vs. iter ( ) {
2426
+ let iter = variant. args . iter ( ) . map ( |aty| subst ( cx, substs, * aty) ) ;
2427
+ r = find_nonrepresentable ( cx, seen, iter) ;
2428
+
2429
+ if r != Representable { break }
2430
+ }
2431
+
2432
+ seen. pop ( ) ;
2433
+ r
2434
+ }
2435
+
2436
+ _ => Representable ,
2379
2437
}
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
2438
}
2387
- }
2388
2439
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
- } ) ;
2440
+ debug ! ( "is_type_representable: {}" ,
2441
+ :: util:: ppaux:: ty_to_str( cx, ty) ) ;
2442
+
2443
+ // To avoid a stack overflow when checking an enum variant or struct that
2444
+ // contains a different, structurally recursive type, maintain a stack
2445
+ // of seen types and check recursion for each of them (issues #3008, #3779).
2446
+ let mut seen: ~[ DefId ] = ~[ ] ;
2447
+ type_structurally_recursive ( cx, & mut seen, ty)
2398
2448
}
2399
2449
2400
2450
pub fn type_is_trait ( ty : t ) -> bool {
0 commit comments