compiler: Calculate optional aggregate layouts from resolved payloads

e8927bdf1c76a4d6cb14e5a477732a7f956edbf19bf11edfc0b65a35f338f0be
Alexis Sellier committed ago 1 parent 9f38500b
lib/std/lang/resolver.rad +9 -8
2021 2021
        case Type::Fn(_) => return Layout { size: PTR_SIZE, alignment: PTR_SIZE },
2022 2022
        case Type::Cell { .. } => return Layout {
2023 2023
            size: PTR_SIZE, alignment: PTR_SIZE
2024 2024
        },
2025 2025
        case Type::Array(arr) => return getArrayLayout(getTypeLayout(*arr.item), arr.length),
2026 -
        case Type::Optional(inner) => return getOptionalLayout(*inner),
2026 +
        case Type::Optional(inner) => {
2027 +
            // Nullable types use null pointer optimization -- no tag byte needed.
2028 +
            if isNullableType(*inner) {
2029 +
                return getTypeLayout(*inner);
2030 +
            }
2031 +
            return getOptionalAggregateLayout(getTypeLayout(*inner));
2032 +
        }
2027 2033
        case Type::Nominal(info) => return getNominalLayout(*info),
2028 2034
        else => {
2029 2035
            panic "getTypeLayout: the given type cannot be layed out";
2030 2036
        }
2031 2037
    }
2051 2057
        size: item.size * length,
2052 2058
        alignment: item.alignment,
2053 2059
    };
2054 2060
}
2055 2061
2056 -
/// Get the layout of an optional type.
2057 -
export unsafe fn getOptionalLayout(inner: Type) -> Layout {
2058 -
    // Nullable types use null pointer optimization -- no tag byte needed.
2059 -
    if isNullableType(inner) {
2060 -
        return getTypeLayout(inner);
2061 -
    }
2062 -
    let innerLayout = getTypeLayout(inner);
2062 +
/// Get an optional aggregate layout from its payload layout.
2063 +
export fn getOptionalAggregateLayout(innerLayout: Layout) -> Layout {
2063 2064
    let valOffset = getOptionalValOffset(innerLayout);
2064 2065
    let alignment = max(innerLayout.alignment, 1);
2065 2066
2066 2067
    return Layout {
2067 2068
        size: mem::alignUp(valOffset + innerLayout.size, alignment),
lib/std/lang/resolver/tests.rad +12 -0
26 26
}
27 27
28 28
/// Synthetic file path used for resolver tests.
29 29
constant MODULE_PATH: *[u8] = "/dev/test.rad";
30 30
31 +
/// Optional aggregate layouts align the tag and payload for safe callers.
32 +
@test fn testOptionalAggregateLayouts() throws (testing::TestError) {
33 +
    for alignment in [1 as u32, 2, 4, 8, 16] {
34 +
        for length in [0 as u32, 1, 3] {
35 +
            let payload = super::Layout { size: length * alignment, alignment };
36 +
            let layout = super::getOptionalAggregateLayout(payload);
37 +
            assert layout.size == (length + 1) * alignment;
38 +
            assert layout.alignment == alignment;
39 +
        }
40 +
    }
41 +
}
42 +
31 43
/// AST arena storage used by resolver tests.
32 44
static AST_ARENA: [u8; 2097152] = [0; 2097152];
33 45
34 46
/// Resolver arena storage used by resolver tests.
35 47
static ARENA_STORAGE: [u8; 2097152] = [0; 2097152];