compiler: Check symbol name registration

41188defdbe674170602e4fca26e54b0df78929c068f838779a1f6883deae936
Alexis Sellier committed ago 1 parent 09f9be49
lib/std/lang/lower.rad +5 -5
972 972
    return il::formatQualifiedName(self.arena, path, name);
973 973
}
974 974
975 975
/// Register the emitted name for a function or data symbol.
976 976
/// Calls and address expressions use this name across package boundaries.
977 -
unsafe fn registerSymbolName 'arena 'phase (self: &mut Lowerer 'arena 'phase, sym: *unsafe resolver::Symbol, qualName: *[u8]) where 'arena: 'phase {
978 -
    self.symbolNames.append(SymbolNameEntry { symbolId: sym.id, qualName }, alloc::arenaAllocator(self.arena));
977 +
fn registerSymbolName(names: &mut *mut [SymbolNameEntry], sym: &resolver::Symbol, qualName: *[u8], allocator: alloc::Allocator) {
978 +
    names.append(SymbolNameEntry { symbolId: sym.id, qualName }, allocator);
979 979
}
980 980
981 981
/// Look up the emitted name for a function or data symbol.
982 982
/// Return `nil` if its declaration has not been lowered.
983 983
// TODO: This is kind of dubious as an optimization, if it depends on the order
1081 1081
    // Build qualified function name for multi-module compilation.
1082 1082
    let qualName = qualifyName(self, nil, name);
1083 1083
1084 1084
    // Register function symbol for cross-package call resolution.
1085 1085
    if let sym = resolver::symbolFor(self.resolver, node) {
1086 -
        registerSymbolName(self, sym, qualName);
1086 +
        registerSymbolName(&mut self.symbolNames, sym, qualName, alloc::arenaAllocator(self.arena));
1087 1087
    }
1088 1088
    let variableSlots = variableStorage(functionArena, data.localCount);
1089 1089
    let parent: 'function = &mut *self, arena = &mut *functionArena, variables = &mut variableSlots[..] where 'phase: 'function in {
1090 1090
        let mut fnLow = fnLowerer(parent, node, fnType, qualName, arena, variables);
1091 1091
1263 1263
    let data = resolver::nodeData(self.resolver, node);
1264 1264
    let case resolver::Type::Fn(fnType) = data.ty else {
1265 1265
        throw LowerError::ExpectedFunction;
1266 1266
    };
1267 1267
    let sym = resolver::symbolFor(self.resolver, node) else throw LowerError::MissingSymbol(node);
1268 -
    registerSymbolName(self, sym, qualName);
1268 +
    registerSymbolName(&mut self.symbolNames, sym, qualName, alloc::arenaAllocator(self.arena));
1269 1269
1270 1270
    let variableSlots = variableStorage(functionArena, data.localCount);
1271 1271
    let parent: 'function = &mut *self, arena = &mut *functionArena, variables = &mut variableSlots[..] where 'phase: 'function in {
1272 1272
        let mut fnLow = fnLowerer(parent, node, fnType, qualName, arena, variables);
1273 1273
        if requiresReturnParam(fnType) {
2061 2061
    let prefix = self.fnName;
2062 2062
    let segments = [prefix, "nominal", sym.name];
2063 2063
    let name = try buildSegmentedName(self.low, &segments[..]);
2064 2064
2065 2065
    let qualified = qualifyName(self.low, nil, name);
2066 -
    registerSymbolName(self.low, sym, qualified);
2066 +
    registerSymbolName(&mut self.low.symbolNames, sym, qualified, alloc::arenaAllocator(self.low.arena));
2067 2067
}
2068 2068
2069 2069
/// Get the next available SSA register.
2070 2070
fn nextReg 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function) -> il::Reg where 'arena: 'phase, 'phase: 'function {
2071 2071
    let reg = il::Reg { n: self.regCounter };
test/tests/symbol.name.registration.rad added +38 -0
1 +
//! returns: 0
2 +
3 +
/// Receiver for a method with function-local data.
4 +
record Source: Copy {
5 +
    /// Index into the method data.
6 +
    index: u32,
7 +
}
8 +
9 +
/// Read the first function's local data.
10 +
fn first(index: u32) -> u32 {
11 +
    constant VALUES: [u32; 3] = [11, 13, 17];
12 +
    return VALUES[index];
13 +
}
14 +
15 +
/// Read distinct local data with the same source name.
16 +
fn second(index: u32) -> u32 {
17 +
    constant VALUES: [u32; 3] = [19, 23, 29];
18 +
    return VALUES[index];
19 +
}
20 +
21 +
/// Read method-local data with the same source name.
22 +
fn (source: &Source) read() -> u32 {
23 +
    constant VALUES: [u32; 3] = [31, 37, 41];
24 +
    return VALUES[source.index];
25 +
}
26 +
27 +
/// Check registered data names through direct, indirect, and method calls.
28 +
@default fn main() -> u32 {
29 +
    let expected = [61 as u32, 73, 87];
30 +
    let readFirst = first;
31 +
    let readSecond = second;
32 +
    for index in 0..3 {
33 +
        let source = Source { index };
34 +
        assert first(index) + second(index) + source.read() == expected[index];
35 +
        assert readSecond(index) + readFirst(index) + source.read() == expected[index];
36 +
    }
37 +
    return 0;
38 +
}