compiler: Check owned record field construction
93dfa95dc1a610c8e771cddd3b5048f479c31971a54a942600a5724f561a6f52
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; |