compiler: Check recursive type layout traversal
0fa50c3442417eb3be1953a2bcd222038d455064a08074f30da961fd4111cf06
1 parent
548a8aa3
lib/std/lang/resolver.rad
+13 -4
| 2117 | 2117 | return b; |
|
| 2118 | 2118 | } |
|
| 2119 | 2119 | ||
| 2120 | 2120 | /// Get the layout of a type. |
|
| 2121 | 2121 | export unsafe fn getTypeLayout(ty: Type) -> Layout { |
|
| 2122 | + | return typeLayout(ty); |
|
| 2123 | + | } |
|
| 2124 | + | ||
| 2125 | + | /// Traverse owned type links and compute array, optional, or fixed layouts. |
|
| 2126 | + | fn typeLayout(ty: Type) -> Layout { |
|
| 2122 | 2127 | match ty { |
|
| 2123 | - | case Type::Array(arr) => return getArrayLayout(getTypeLayout(*arr.item), arr.length), |
|
| 2128 | + | case Type::Array(arr) => return getArrayLayout(typeLayout(*arr.item), arr.length), |
|
| 2124 | 2129 | case Type::Optional(inner) => { |
|
| 2125 | 2130 | // Nullable types use null pointer optimization -- no tag byte needed. |
|
| 2126 | 2131 | if isNullableType(*inner) { |
|
| 2127 | - | return getTypeLayout(*inner); |
|
| 2132 | + | return typeLayout(*inner); |
|
| 2128 | 2133 | } |
|
| 2129 | - | return getOptionalAggregateLayout(getTypeLayout(*inner)); |
|
| 2134 | + | return getOptionalAggregateLayout(typeLayout(*inner)); |
|
| 2130 | 2135 | } |
|
| 2131 | - | case Type::Nominal(info) => return getNominalLayout(*info), |
|
| 2136 | + | case Type::Nominal(info) => { |
|
| 2137 | + | unsafe { |
|
| 2138 | + | return getNominalLayout(*info); |
|
| 2139 | + | } |
|
| 2140 | + | }, |
|
| 2132 | 2141 | else => return fixedTypeLayout(ty), |
|
| 2133 | 2142 | } |
|
| 2134 | 2143 | } |
|
| 2135 | 2144 | ||
| 2136 | 2145 | /// Get a layout that does not depend on nested type or nominal metadata. |
lib/std/lang/resolver/tests.rad
+11 -1
| 306 | 306 | assert array.size == size * length and array.alignment == alignment; |
|
| 307 | 307 | } |
|
| 308 | 308 | let optional = super::getTypeLayout(super::Type::Optional(item)); |
|
| 309 | 309 | let expected = layout if super::isNullableType(ty) else super::getOptionalAggregateLayout(layout); |
|
| 310 | 310 | assert optional.size == expected.size and optional.alignment == expected.alignment; |
|
| 311 | + | let optionalStorage = try! alloc::alloc(&mut arena, @sizeOf(super::Type), @alignOf(super::Type)) as *mut super::Type; |
|
| 312 | + | set *optionalStorage = super::Type::Optional(item); |
|
| 313 | + | let optionalItem: *super::Type = optionalStorage; |
|
| 314 | + | for length in [0 as u32, 1, 3] { |
|
| 315 | + | let array = super::getTypeLayout(super::Type::Array(super::ArrayType { item: optionalItem, length })); |
|
| 316 | + | assert array.size == optional.size * length and array.alignment == optional.alignment; |
|
| 317 | + | } |
|
| 318 | + | let nested = super::getTypeLayout(super::Type::Optional(optionalItem)); |
|
| 319 | + | let nestedExpected = super::getOptionalAggregateLayout(optional); |
|
| 320 | + | assert nested.size == nestedExpected.size and nested.alignment == nestedExpected.alignment; |
|
| 311 | 321 | } |
|
| 312 | 322 | ||
| 313 | - | /// Storage for one owned type used by array and optional layout fixtures. |
|
| 323 | + | /// Storage for owned types used by array and optional layout fixtures. |
|
| 314 | 324 | static FIXED_LAYOUT_STORAGE: [u8; 256] = [0; 256]; |
|
| 315 | 325 | ||
| 316 | 326 | /// Array layouts retain element alignment for empty and populated arrays. |
|
| 317 | 327 | @test fn testArrayLayoutFromElementLayout() throws (testing::TestError) { |
|
| 318 | 328 | for alignment in [1 as u32, 2, 4, 8, 16] { |