compiler: Construct v-table data in checked code
e76df48f7127abc2a52caaa8de104533ae6f1d5779782b0c4fc6e3eddd8bdcb0
1 parent
508ce34e
lib/std/lang/lower.rad
+18 -13
| 1221 | 1221 | } |
|
| 1222 | 1222 | } |
|
| 1223 | 1223 | ||
| 1224 | 1224 | // Create v-table in data section, used for dynamic dispatch. |
|
| 1225 | 1225 | let vName = vtableName(self, nil, typeName, tName); |
|
| 1226 | - | let values = try! alloc::allocSlice( |
|
| 1227 | - | self.arena, @sizeOf(il::DataValue), @alignOf(il::DataValue), traitInfo.methods.len as u32 |
|
| 1228 | - | ) as *mut [il::DataValue]; |
|
| 1226 | + | let allocator = alloc::arenaAllocator(self.arena); |
|
| 1227 | + | let data = vtableData(vName, &state.methodNames[..traitInfo.methods.len], allocator); |
|
| 1228 | + | self.data.append(data, allocator); |
|
| 1229 | + | return nil; |
|
| 1230 | + | } |
|
| 1229 | 1231 | ||
| 1230 | - | for i in 0..traitInfo.methods.len { |
|
| 1231 | - | set values[i] = il::DataValue { |
|
| 1232 | - | item: il::DataItem::Fn(state.methodNames[i]), |
|
| 1232 | + | /// Construct read-only v-table data in method-index order. |
|
| 1233 | + | fn vtableData(name: *[u8], methods: &[*[u8]], allocator: alloc::Allocator) -> il::Data { |
|
| 1234 | + | let mut builder = dataBuilder(allocator); |
|
| 1235 | + | for method in methods { |
|
| 1236 | + | dataBuilderPush(&mut builder, il::DataValue { |
|
| 1237 | + | item: il::DataItem::Fn(method), |
|
| 1233 | 1238 | count: 1, |
|
| 1234 | - | }; |
|
| 1239 | + | }); |
|
| 1235 | 1240 | } |
|
| 1236 | - | self.data.append(il::Data { |
|
| 1237 | - | name: vName, |
|
| 1238 | - | size: traitInfo.methods.len as u32 * resolver::PTR_SIZE, |
|
| 1241 | + | let result = dataBuilderFinish(builder); |
|
| 1242 | + | return il::Data { |
|
| 1243 | + | name, |
|
| 1244 | + | size: methods.len * resolver::PTR_SIZE, |
|
| 1239 | 1245 | alignment: resolver::PTR_SIZE, |
|
| 1240 | 1246 | readOnly: true, |
|
| 1241 | 1247 | isZeroInit: false, |
|
| 1242 | - | values: &values[..traitInfo.methods.len as u32], |
|
| 1243 | - | }, alloc::arenaAllocator(self.arena)); |
|
| 1244 | - | return nil; |
|
| 1248 | + | values: result.values, |
|
| 1249 | + | }; |
|
| 1245 | 1250 | } |
|
| 1246 | 1251 | ||
| 1247 | 1252 | /// Lower a method node into an IL function with the given qualified name. |
|
| 1248 | 1253 | /// Shared by both instance methods and standalone methods. |
|
| 1249 | 1254 | unsafe fn lowerMethod 'arena 'phase ( |
test/tests/trait.supertrait.forward.rad
+19 -0
| 7 | 7 | ||
| 8 | 8 | trait Parent { |
|
| 9 | 9 | unsafe fn (*unsafe Parent) parent() -> i32; |
|
| 10 | 10 | } |
|
| 11 | 11 | ||
| 12 | + | /// A third level combines both inherited methods with its own method. |
|
| 13 | + | trait Grandchild: Child { |
|
| 14 | + | /// Read a value distinct from both inherited results. |
|
| 15 | + | unsafe fn (*unsafe Grandchild) grandchild() -> i32; |
|
| 16 | + | } |
|
| 17 | + | ||
| 12 | 18 | record Value: Copy { |
|
| 13 | 19 | n: i32, |
|
| 14 | 20 | } |
|
| 15 | 21 | ||
| 16 | 22 | instance Parent for Value { |
| 23 | 29 | unsafe fn (self: *unsafe Value) child() -> i32 { |
|
| 24 | 30 | return self.n + 1; |
|
| 25 | 31 | } |
|
| 26 | 32 | } |
|
| 27 | 33 | ||
| 34 | + | /// Supply the final slot of the three-level v-table. |
|
| 35 | + | instance Grandchild for Value { |
|
| 36 | + | /// Return the value for the final dispatch slot. |
|
| 37 | + | unsafe fn (self: *unsafe Value) grandchild() -> i32 { |
|
| 38 | + | return self.n + 2; |
|
| 39 | + | } |
|
| 40 | + | } |
|
| 41 | + | ||
| 28 | 42 | @default unsafe fn main() -> i32 { |
|
| 29 | 43 | let value = Value { n: 41 }; |
|
| 30 | 44 | let object: *unsafe opaque Child = &value; |
|
| 31 | 45 | assert object.parent() == 41; |
|
| 32 | 46 | assert object.child() == 42; |
|
| 47 | + | let combined: *unsafe opaque Grandchild = &value; |
|
| 48 | + | assert combined.parent() == 41; |
|
| 49 | + | assert combined.child() == 42; |
|
| 50 | + | assert combined.grandchild() == 43; |
|
| 51 | + | assert combined.parent() == 41; |
|
| 33 | 52 | return 0; |
|
| 34 | 53 | } |