Handle scoped access constants in lowerer
9f542472d6d40fb6cb881aa6fd47a7e2922c0447fb269981cfefdb2a08ab793c
1 parent
51330bdd
lib/std/lang/lower.rad
+50 -22
| 1215 | 1215 | set irTyp = ilType(self, typ); |
|
| 1216 | 1216 | } |
|
| 1217 | 1217 | return il::DataItem::Val { typ: irTyp, val: constToScalar(val) }; |
|
| 1218 | 1218 | } |
|
| 1219 | 1219 | ||
| 1220 | + | /// Lower scalar-like constant nodes into data values, including fallback handling |
|
| 1221 | + | /// for void-variant tags and slice string initializers. |
|
| 1222 | + | fn lowerConstScalarDataInto( |
|
| 1223 | + | self: *mut Lowerer, |
|
| 1224 | + | node: *ast::Node, |
|
| 1225 | + | ty: resolver::Type, |
|
| 1226 | + | dataPrefix: *[u8], |
|
| 1227 | + | b: *mut DataValueBuilder |
|
| 1228 | + | ) throws (LowerError) { |
|
| 1229 | + | let val = resolver::constValueEntry(self.resolver, node) else { |
|
| 1230 | + | if let idx = voidVariantIndex(self.resolver, node) { |
|
| 1231 | + | dataBuilderPush(b, il::DataValue { |
|
| 1232 | + | item: il::DataItem::Val { typ: il::Type::W8, val: idx }, |
|
| 1233 | + | count: 1 |
|
| 1234 | + | }); |
|
| 1235 | + | return; |
|
| 1236 | + | } |
|
| 1237 | + | throw LowerError::MissingConst(node); |
|
| 1238 | + | }; |
|
| 1239 | + | ||
| 1240 | + | if let case resolver::ConstValue::String(s) = val { |
|
| 1241 | + | if let case resolver::Type::Slice { .. } = ty { |
|
| 1242 | + | let strSym = try getOrCreateStringData(self, s, dataPrefix); |
|
| 1243 | + | dataSliceHeader(b, strSym, s.len); |
|
| 1244 | + | return; |
|
| 1245 | + | } |
|
| 1246 | + | } |
|
| 1247 | + | dataBuilderPush(b, il::DataValue { |
|
| 1248 | + | item: constValueToDataItem(self, val, ty), |
|
| 1249 | + | count: 1 |
|
| 1250 | + | }); |
|
| 1251 | + | } |
|
| 1252 | + | ||
| 1220 | 1253 | /// Lower a constant or static declaration to the data section. |
|
| 1221 | 1254 | fn lowerDataDecl( |
|
| 1222 | 1255 | self: *mut Lowerer, |
|
| 1223 | 1256 | node: *ast::Node, |
|
| 1224 | 1257 | value: *ast::Node, |
| 1352 | 1385 | case resolver::SymbolData::Variant { .. } => |
|
| 1353 | 1386 | try lowerConstUnionVariantInto(self, node, calleeSym, ty, call.args, dataPrefix, b), |
|
| 1354 | 1387 | case resolver::SymbolData::Type(resolver::NominalType::Record(recInfo)) => { |
|
| 1355 | 1388 | try lowerConstRecordCtorInto(self, call.args, recInfo, dataPrefix, b); |
|
| 1356 | 1389 | } |
|
| 1357 | - | else => throw LowerError::MissingConst(node), |
|
| 1390 | + | else => throw LowerError::MissingConst(node) |
|
| 1358 | 1391 | } |
|
| 1359 | 1392 | } |
|
| 1360 | 1393 | case ast::NodeValue::AddressOf(addr) => { |
|
| 1361 | 1394 | try lowerConstAddressSliceInto(self, addr, ty, dataPrefix, b); |
|
| 1362 | 1395 | } |
| 1367 | 1400 | let case ast::NodeValue::ConstDecl(decl) = sym.node.value |
|
| 1368 | 1401 | else throw LowerError::MissingConst(node); |
|
| 1369 | 1402 | ||
| 1370 | 1403 | try lowerConstDataInto(self, decl.value, ty, slotSize, dataPrefix, b); |
|
| 1371 | 1404 | }, |
|
| 1372 | - | else => { |
|
| 1373 | - | // Scalar values: integers, bools, strings, void union variants, etc. |
|
| 1374 | - | let val = resolver::constValueEntry(self.resolver, node) |
|
| 1375 | - | else throw LowerError::MissingConst(node); |
|
| 1376 | - | ||
| 1377 | - | if let case resolver::ConstValue::String(s) = val { |
|
| 1378 | - | if let case resolver::Type::Slice { .. } = ty { |
|
| 1379 | - | let strSym = try getOrCreateStringData(self, s, dataPrefix); |
|
| 1380 | - | dataSliceHeader(b, strSym, s.len); |
|
| 1381 | - | } else { |
|
| 1382 | - | dataBuilderPush(b, il::DataValue { |
|
| 1383 | - | item: constValueToDataItem(self, val, ty), |
|
| 1384 | - | count: 1 |
|
| 1385 | - | }); |
|
| 1386 | - | } |
|
| 1405 | + | case ast::NodeValue::ScopeAccess(_) => { |
|
| 1406 | + | let sym = resolver::nodeData(self.resolver, node).sym |
|
| 1407 | + | else throw LowerError::MissingSymbol(node); |
|
| 1408 | + | if let case ast::NodeValue::ConstDecl(decl) = sym.node.value { |
|
| 1409 | + | try lowerConstDataInto(self, decl.value, ty, slotSize, dataPrefix, b); |
|
| 1387 | 1410 | } else { |
|
| 1388 | - | dataBuilderPush(b, il::DataValue { |
|
| 1389 | - | item: constValueToDataItem(self, val, ty), |
|
| 1390 | - | count: 1 |
|
| 1391 | - | }); |
|
| 1411 | + | try lowerConstScalarDataInto(self, node, ty, dataPrefix, b); |
|
| 1392 | 1412 | } |
|
| 1393 | 1413 | } |
|
| 1414 | + | else => { |
|
| 1415 | + | // Scalar values: integers, bools, strings, void union variants, etc. |
|
| 1416 | + | try lowerConstScalarDataInto(self, node, ty, dataPrefix, b); |
|
| 1417 | + | } |
|
| 1394 | 1418 | } |
|
| 1395 | 1419 | // Pad to fill the slot. |
|
| 1396 | 1420 | let padding = slotSize - layout.size; |
|
| 1397 | 1421 | if padding > 0 { |
|
| 1398 | 1422 | dataBuilderPush(b, il::DataValue { item: il::DataItem::Undef, count: padding }); |
| 6757 | 6781 | let sym = data.sym else { |
|
| 6758 | 6782 | throw LowerError::MissingSymbol(node); |
|
| 6759 | 6783 | }; |
|
| 6760 | 6784 | match sym.data { |
|
| 6761 | 6785 | case resolver::SymbolData::Variant { index, .. } => { |
|
| 6786 | + | let mut indexValue = index as i64; |
|
| 6787 | + | if let idx = voidVariantIndex(self.low.resolver, node) { |
|
| 6788 | + | set indexValue = idx; |
|
| 6789 | + | } |
|
| 6762 | 6790 | // Void union variant like `Option::None`. |
|
| 6763 | 6791 | if data.ty == resolver::Type::Unknown { |
|
| 6764 | 6792 | throw LowerError::MissingType(node); |
|
| 6765 | 6793 | } |
|
| 6766 | 6794 | // All-void unions are passed as scalars (the tag byte). |
|
| 6767 | 6795 | // Return an immediate instead of building a tagged aggregate. |
|
| 6768 | 6796 | if resolver::isVoidUnion(data.ty) { |
|
| 6769 | - | return il::Val::Imm(index as i64); |
|
| 6797 | + | return il::Val::Imm(indexValue); |
|
| 6770 | 6798 | } |
|
| 6771 | 6799 | let unionInfo = unionInfoFromType(data.ty) else { |
|
| 6772 | 6800 | throw LowerError::MissingMetadata; |
|
| 6773 | 6801 | }; |
|
| 6774 | 6802 | let valOffset = unionInfo.valOffset as i32; |
|
| 6775 | - | return try buildTagged(self, resolver::getTypeLayout(data.ty), index as i64, nil, resolver::Type::Void, 1, valOffset); |
|
| 6803 | + | return try buildTagged(self, resolver::getTypeLayout(data.ty), indexValue, nil, resolver::Type::Void, 1, valOffset); |
|
| 6776 | 6804 | } |
|
| 6777 | 6805 | case resolver::SymbolData::Constant { type, .. } => { |
|
| 6778 | 6806 | // Constant without compile-time value (e.g. record constant); |
|
| 6779 | 6807 | // load from data section. |
|
| 6780 | 6808 | let src = emitDataAddr(self, sym); |
test/tests/lower.const.record.ident.rad
added
+18 -0
| 1 | + | record Reg(u8); |
|
| 2 | + | ||
| 3 | + | constant A0: Reg = Reg(10); |
|
| 4 | + | constant A1: Reg = Reg(11); |
|
| 5 | + | ||
| 6 | + | record Entry { |
|
| 7 | + | name: *[u8], |
|
| 8 | + | reg: Reg, |
|
| 9 | + | } |
|
| 10 | + | ||
| 11 | + | constant ENTRIES: [Entry; 2] = [ |
|
| 12 | + | { name: "a0", reg: A0 }, |
|
| 13 | + | { name: "a1", reg: A1 }, |
|
| 14 | + | ]; |
|
| 15 | + | ||
| 16 | + | @default fn main() -> i32 { |
|
| 17 | + | return ENTRIES.len as i32; |
|
| 18 | + | } |
test/tests/lower.private.union.const.rad
added
+18 -0
| 1 | + | union Kind { |
|
| 2 | + | A, |
|
| 3 | + | B, |
|
| 4 | + | } |
|
| 5 | + | ||
| 6 | + | record Entry { |
|
| 7 | + | name: *[u8], |
|
| 8 | + | kind: Kind, |
|
| 9 | + | } |
|
| 10 | + | ||
| 11 | + | constant ENTRIES: [Entry; 2] = [ |
|
| 12 | + | { name: "a", kind: Kind::A }, |
|
| 13 | + | { name: "b", kind: Kind::B }, |
|
| 14 | + | ]; |
|
| 15 | + | ||
| 16 | + | @default fn main() -> i32 { |
|
| 17 | + | return ENTRIES.len as i32; |
|
| 18 | + | } |
test/tests/lower.record.scalar.record.const.rad
added
+15 -0
| 1 | + | record Reg(u8); |
|
| 2 | + | ||
| 3 | + | record Entry { |
|
| 4 | + | name: *[u8], |
|
| 5 | + | reg: Reg, |
|
| 6 | + | } |
|
| 7 | + | ||
| 8 | + | constant ENTRIES: [Entry; 2] = [ |
|
| 9 | + | { name: "a0", reg: Reg(10) }, |
|
| 10 | + | { name: "a1", reg: Reg(11) }, |
|
| 11 | + | ]; |
|
| 12 | + | ||
| 13 | + | @default fn main() -> i32 { |
|
| 14 | + | return ENTRIES.len as i32; |
|
| 15 | + | } |