compiler: Check result and union layout traversal
5cea34bf6d2b22ed186323e439db71a79278659b04f54540cd406ee25921519a
1 parent
0fa50c34
lib/std/lang/resolver.rad
+9 -4
| 2254 | 2254 | } |
|
| 2255 | 2255 | } |
|
| 2256 | 2256 | ||
| 2257 | 2257 | /// Get the layout of a result aggregate with a tag and the larger payload. |
|
| 2258 | 2258 | export unsafe fn getResultLayout(payload: Type, throwList: *[*Type]) -> Layout { |
|
| 2259 | - | let payloadLayout = getTypeLayout(payload); |
|
| 2259 | + | return resultLayout(payload, throwList); |
|
| 2260 | + | } |
|
| 2261 | + | ||
| 2262 | + | /// Compute tagged result storage while borrowing its error type table. |
|
| 2263 | + | fn resultLayout(payload: Type, throwList: &[*Type]) -> Layout { |
|
| 2264 | + | let payloadLayout = typeLayout(payload); |
|
| 2260 | 2265 | let mut maxSize = payloadLayout.size; |
|
| 2261 | 2266 | let mut maxAlign = payloadLayout.alignment; |
|
| 2262 | 2267 | ||
| 2263 | 2268 | for errType in throwList { |
|
| 2264 | - | let errLayout = getTypeLayout(*errType); |
|
| 2269 | + | let errLayout = typeLayout(*errType); |
|
| 2265 | 2270 | set maxSize = max(maxSize, errLayout.size); |
|
| 2266 | 2271 | set maxAlign = max(maxAlign, errLayout.alignment); |
|
| 2267 | 2272 | } |
|
| 2268 | 2273 | return Layout { |
|
| 2269 | 2274 | size: PTR_SIZE + maxSize, |
|
| 2270 | 2275 | alignment: max(PTR_SIZE, maxAlign), |
|
| 2271 | 2276 | }; |
|
| 2272 | 2277 | } |
|
| 2273 | 2278 | ||
| 2274 | 2279 | /// Compute the layout for a union given its resolved variants. |
|
| 2275 | - | unsafe fn computeUnionLayout(variants: *unsafe [UnionVariant]) -> UnionLayoutInfo { |
|
| 2280 | + | fn computeUnionLayout(variants: &[UnionVariant]) -> UnionLayoutInfo { |
|
| 2276 | 2281 | let tagSize: u32 = 1; |
|
| 2277 | 2282 | let mut maxVarSize: u32 = 0; |
|
| 2278 | 2283 | let mut maxVarAlign: u32 = 1; |
|
| 2279 | 2284 | let mut isAllVoid: bool = true; |
|
| 2280 | 2285 | ||
| 2281 | 2286 | for variant in variants { |
|
| 2282 | 2287 | if variant.valueType <> Type::Void { |
|
| 2283 | 2288 | set isAllVoid = false; |
|
| 2284 | - | let payloadLayout = getTypeLayout(variant.valueType); |
|
| 2289 | + | let payloadLayout = typeLayout(variant.valueType); |
|
| 2285 | 2290 | set maxVarSize = max(maxVarSize, payloadLayout.size); |
|
| 2286 | 2291 | set maxVarAlign = max(maxVarAlign, payloadLayout.alignment); |
|
| 2287 | 2292 | } |
|
| 2288 | 2293 | } |
|
| 2289 | 2294 | let unionAlignment: u32 = max(1, maxVarAlign); |
lib/std/lang/resolver/tests.rad
+20 -1
| 257 | 257 | assert err.kind == super::ErrorKind::ImmutableBinding, program; |
|
| 258 | 258 | } |
|
| 259 | 259 | } |
|
| 260 | 260 | } |
|
| 261 | 261 | ||
| 262 | - | /// Fixed layouts cover primitive and pointer-like representations. |
|
| 262 | + | /// Fixed and result layouts cover primitive and pointer-like representations. |
|
| 263 | 263 | @test unsafe fn testFixedTypeLayouts() throws (testing::TestError) { |
|
| 264 | 264 | for ty in [super::Type::Void, super::Type::Never] { |
|
| 265 | 265 | checkFixedTypeLayout(ty, 0, 0); |
|
| 266 | 266 | } |
|
| 267 | 267 | for ty in [super::Type::Bool, super::Type::U8, super::Type::I8] { |
| 289 | 289 | checkFixedTypeLayout(super::Type::Pointer { class, target: item, mutable }, 8, 8); |
|
| 290 | 290 | checkFixedTypeLayout(super::Type::Slice { class, item, mutable }, 16, 8); |
|
| 291 | 291 | checkFixedTypeLayout(super::Type::TraitObject { class, traitInfo: &traitInfo, mutable }, 16, 8); |
|
| 292 | 292 | } |
|
| 293 | 293 | } |
|
| 294 | + | /// Result layouts retain the tag and the largest success or error payload. |
|
| 295 | + | let errors = try! alloc::allocSlice(&mut arena, @sizeOf(*super::Type), @alignOf(*super::Type), 3) |
|
| 296 | + | as *mut [*super::Type]; |
|
| 297 | + | for ty, i in [super::Type::Void, super::Type::U8, super::Type::U64] { |
|
| 298 | + | let slot = try! alloc::alloc(&mut arena, @sizeOf(super::Type), @alignOf(super::Type)) as *mut super::Type; |
|
| 299 | + | set *slot = ty; |
|
| 300 | + | set errors[i] = slot; |
|
| 301 | + | } |
|
| 302 | + | let throwList: *[*super::Type] = errors; |
|
| 303 | + | let payloads = [super::Type::Void, super::Type::U8, |
|
| 304 | + | super::Type::Array(super::ArrayType { item: throwList[2], length: 3 })]; |
|
| 305 | + | let emptySizes: [u32; 3] = [8, 9, 32]; |
|
| 306 | + | let errorSizes: [u32; 3] = [16, 16, 32]; |
|
| 307 | + | for payload, i in payloads { |
|
| 308 | + | let empty = super::getResultLayout(payload, &[]); |
|
| 309 | + | assert empty.size == emptySizes[i] and empty.alignment == 8; |
|
| 310 | + | let result = super::getResultLayout(payload, throwList); |
|
| 311 | + | assert result.size == errorSizes[i] and result.alignment == 8; |
|
| 312 | + | } |
|
| 294 | 313 | } |
|
| 295 | 314 | ||
| 296 | 315 | /// Check a fixed layout through direct, array, and optional type traversal. |
|
| 297 | 316 | unsafe fn checkFixedTypeLayout(ty: super::Type, size: u32, alignment: u32) { |
|
| 298 | 317 | let layout = super::getTypeLayout(ty); |