compiler: Check result and union layout traversal

5cea34bf6d2b22ed186323e439db71a79278659b04f54540cd406ee25921519a
Alexis Sellier committed ago 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);