compiler: Check recursive type layout traversal

0fa50c3442417eb3be1953a2bcd222038d455064a08074f30da961fd4111cf06
Alexis Sellier committed ago 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] {