compiler: Check owned record field construction

93dfa95dc1a610c8e771cddd3b5048f479c31971a54a942600a5724f561a6f52
Alexis Sellier committed ago 1 parent 5cea34bf
lib/std/lang/resolver.rad +20 -17
4842 4842
/// Resolve record fields from a node list.
4843 4843
unsafe fn resolveRecordFields 'arena (self: &mut Resolver 'arena, node: *ast::Node, fields: *[*ast::Node], labeled: bool) -> RecordType
4844 4844
    throws (ResolveError)
4845 4845
{
4846 4846
    let a = alloc::arenaAllocator(self.arena);
4847 -
    let mut result: *unsafe mut [RecordField] = &mut [];
4848 -
    let mut currentOffset: u32 = 0;
4849 -
    let mut maxAlignment: u32 = 1;
4847 +
    let mut result: *mut [RecordField] = &mut [];
4848 +
    let mut layout = Layout { size: 0, alignment: 1 };
4850 4849
4851 4850
    if fields.len > parser::MAX_RECORD_FIELDS {
4852 4851
        throw emitError(self, node, ErrorKind::Internal);
4853 4852
    }
4854 4853
    for field in fields {
4874 4873
            else throw emitError(self, typeNode, ErrorKind::CannotInferType);
4875 4874
4876 4875
        // Ensure field type is fully resolved before computing layout.
4877 4876
        try ensureTypeResolved(self, fieldType, typeNode);
4878 4877
4879 -
        // Compute field offset by aligning to field's alignment.
4880 -
        let fieldLayout = getTypeLayout(fieldType);
4881 -
        set currentOffset = mem::alignUp(currentOffset, fieldLayout.alignment);
4882 -
4883 -
        result.append(RecordField { name: fieldName, fieldType, offset: currentOffset as i32 }, a);
4884 -
4885 -
        // Advance offset past this field.
4886 -
        set currentOffset += fieldLayout.size;
4887 -
4888 -
        // Track max alignment for record layout.
4889 -
        set maxAlignment = max(maxAlignment, fieldLayout.alignment);
4878 +
        appendRecordField(&mut result, &mut layout, fieldName, fieldType, a);
4890 4879
    }
4891 4880
    // Compute cached layout.
4892 4881
    let recordLayout = Layout {
4893 -
        size: mem::alignUp(currentOffset, maxAlignment),
4894 -
        alignment: maxAlignment
4882 +
        size: mem::alignUp(layout.size, layout.alignment),
4883 +
        alignment: layout.alignment
4895 4884
    };
4896 4885
    return RecordType {
4897 4886
        regions: nil,
4898 4887
        application: nil,
4899 -
        fields: &result[..],
4888 +
        fields: (&result[..]) as *unsafe [RecordField],
4900 4889
        labeled,
4901 4890
        layout: allocLayout(self, recordLayout),
4902 4891
        declaredLinear: false,
4903 4892
        declaredCopy: false,
4904 4893
    };
4905 4894
}
4906 4895
4896 +
/// Append an owned record field and update the layout before tail padding.
4897 +
fn appendRecordField(fields: &mut *mut [RecordField], layout: &mut Layout, name: ?*[u8], fieldType: Type, allocator: alloc::Allocator) {
4898 +
    // Compute field offset by aligning to field's alignment.
4899 +
    let fieldLayout = typeLayout(fieldType);
4900 +
    let offset = mem::alignUp(layout.size, fieldLayout.alignment);
4901 +
    fields.append(RecordField { name, fieldType, offset: offset as i32 }, allocator);
4902 +
4903 +
    // Advance offset past this field.
4904 +
    set layout.size = offset + fieldLayout.size;
4905 +
4906 +
    // Track max alignment for record layout.
4907 +
    set layout.alignment = max(layout.alignment, fieldLayout.alignment);
4908 +
}
4909 +
4907 4910
/// Resolve record field types for a named record declaration.
4908 4911
unsafe fn resolveRecordBody 'arena (self: &mut Resolver 'arena, node: *ast::Node, decl: ast::RecordDecl)
4909 4912
    throws (ResolveError)
4910 4913
{
4911 4914
    let previous = self.regionScope;