compiler: Construct v-table data in checked code

e76df48f7127abc2a52caaa8de104533ae6f1d5779782b0c4fc6e3eddd8bdcb0
Alexis Sellier committed ago 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
}