compiler: Check symbol name registration
41188defdbe674170602e4fca26e54b0df78929c068f838779a1f6883deae936
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 | + | } |