Fix lowering of void union variant in constant
6d59132f5ff1fc6ab5aeb22087349fd934102d27eafb0e79b8d2309900c12d7c
1 parent
19dc94b6
lib/std/lang/lower.rad
+10 -0
| 1353 | 1353 | dataBuilderPush(b, il::DataValue { |
|
| 1354 | 1354 | item: il::DataItem::Fn(qualName), count: 1, |
|
| 1355 | 1355 | }); |
|
| 1356 | 1356 | return; |
|
| 1357 | 1357 | } |
|
| 1358 | + | // In constant data, a void variant of a mixed union still occupies the |
|
| 1359 | + | // full tagged-union slot. Emitting only the tag corrupts following fields. |
|
| 1360 | + | if let sym = resolver::nodeData(self.resolver, node).sym { |
|
| 1361 | + | if let case resolver::SymbolData::Variant { type: resolver::Type::Void, .. } = sym.data { |
|
| 1362 | + | if let case resolver::Type::Nominal(resolver::NominalType::Union(_)) = ty { |
|
| 1363 | + | try lowerConstUnionVariantInto(self, node, sym, ty, &mut [], dataPrefix, b); |
|
| 1364 | + | return; |
|
| 1365 | + | } |
|
| 1366 | + | } |
|
| 1367 | + | } |
|
| 1358 | 1368 | let layout = resolver::getTypeLayout(ty); |
|
| 1359 | 1369 | ||
| 1360 | 1370 | match node.value { |
|
| 1361 | 1371 | case ast::NodeValue::Undef => { |
|
| 1362 | 1372 | dataBuilderPush(b, il::DataValue { |
test/tests/const.union.payload.fn.array.rad
added
+52 -0
| 1 | + | //! returns: 0 |
|
| 2 | + | //! Constant array of records containing union variants with throwing function payloads. |
|
| 3 | + | ||
| 4 | + | union TestError { |
|
| 5 | + | Fail, |
|
| 6 | + | } |
|
| 7 | + | ||
| 8 | + | fn add(a: i32, b: i32) -> i32 throws (TestError) { |
|
| 9 | + | return a + b; |
|
| 10 | + | } |
|
| 11 | + | ||
| 12 | + | fn sub(a: i32, b: i32) -> i32 throws (TestError) { |
|
| 13 | + | return a - b; |
|
| 14 | + | } |
|
| 15 | + | ||
| 16 | + | union Handler { |
|
| 17 | + | Binary { op: fn(i32, i32) -> i32 throws (TestError) }, |
|
| 18 | + | None, |
|
| 19 | + | } |
|
| 20 | + | ||
| 21 | + | record Entry { |
|
| 22 | + | handler: Handler, |
|
| 23 | + | } |
|
| 24 | + | ||
| 25 | + | constant ENTRIES: [Entry; 3] = [ |
|
| 26 | + | Entry { handler: Handler::None }, |
|
| 27 | + | Entry { handler: Handler::Binary { op: add } }, |
|
| 28 | + | Entry { handler: Handler::Binary { op: sub } }, |
|
| 29 | + | ]; |
|
| 30 | + | ||
| 31 | + | @default fn main() -> i32 { |
|
| 32 | + | match ENTRIES[0].handler { |
|
| 33 | + | case Handler::None => {} |
|
| 34 | + | else => return 1, |
|
| 35 | + | } |
|
| 36 | + | ||
| 37 | + | match ENTRIES[1].handler { |
|
| 38 | + | case Handler::Binary { op } => { |
|
| 39 | + | assert try! op(20, 22) == 42; |
|
| 40 | + | } |
|
| 41 | + | case Handler::None => return 2, |
|
| 42 | + | } |
|
| 43 | + | ||
| 44 | + | match ENTRIES[2].handler { |
|
| 45 | + | case Handler::Binary { op } => { |
|
| 46 | + | assert try! op(50, 8) == 42; |
|
| 47 | + | } |
|
| 48 | + | case Handler::None => return 3, |
|
| 49 | + | } |
|
| 50 | + | ||
| 51 | + | return 0; |
|
| 52 | + | } |
test/tests/const.union.payload.record.array.rad
added
+59 -0
| 1 | + | //! returns: 0 |
|
| 2 | + | //! Constant array of records containing union variants with record payloads. |
|
| 3 | + | ||
| 4 | + | union InstrSpec { |
|
| 5 | + | Empty, |
|
| 6 | + | Small { flag: bool }, |
|
| 7 | + | Imm { opcode: u32, funct3: u32, imm: i32 }, |
|
| 8 | + | Reg { opcode: u32, funct3: u32, funct7: u32 }, |
|
| 9 | + | } |
|
| 10 | + | ||
| 11 | + | record Entry { |
|
| 12 | + | name: *[u8], |
|
| 13 | + | spec: InstrSpec, |
|
| 14 | + | } |
|
| 15 | + | ||
| 16 | + | constant ENTRIES: [Entry; 4] = [ |
|
| 17 | + | Entry { name: "empty", spec: InstrSpec::Empty }, |
|
| 18 | + | Entry { name: "small", spec: InstrSpec::Small { flag: true } }, |
|
| 19 | + | Entry { name: "addi", spec: InstrSpec::Imm { opcode: 0x13, funct3: 0, imm: -7 } }, |
|
| 20 | + | Entry { name: "add", spec: InstrSpec::Reg { opcode: 0x33, funct3: 0, funct7: 0 } }, |
|
| 21 | + | ]; |
|
| 22 | + | ||
| 23 | + | @default fn main() -> i32 { |
|
| 24 | + | match ENTRIES[0].spec { |
|
| 25 | + | case InstrSpec::Empty => {} |
|
| 26 | + | else => return 1, |
|
| 27 | + | } |
|
| 28 | + | assert ENTRIES[0].name[0] == 'e'; |
|
| 29 | + | ||
| 30 | + | match ENTRIES[1].spec { |
|
| 31 | + | case InstrSpec::Small { flag } => { |
|
| 32 | + | assert flag; |
|
| 33 | + | } |
|
| 34 | + | else => return 2, |
|
| 35 | + | } |
|
| 36 | + | assert ENTRIES[1].name[0] == 's'; |
|
| 37 | + | ||
| 38 | + | match ENTRIES[2].spec { |
|
| 39 | + | case InstrSpec::Imm { opcode, funct3, imm } => { |
|
| 40 | + | assert opcode == 0x13; |
|
| 41 | + | assert funct3 == 0; |
|
| 42 | + | assert imm == -7; |
|
| 43 | + | } |
|
| 44 | + | else => return 3, |
|
| 45 | + | } |
|
| 46 | + | assert ENTRIES[2].name[0] == 'a'; |
|
| 47 | + | ||
| 48 | + | match ENTRIES[3].spec { |
|
| 49 | + | case InstrSpec::Reg { opcode, funct3, funct7 } => { |
|
| 50 | + | assert opcode == 0x33; |
|
| 51 | + | assert funct3 == 0; |
|
| 52 | + | assert funct7 == 0; |
|
| 53 | + | } |
|
| 54 | + | else => return 4, |
|
| 55 | + | } |
|
| 56 | + | assert ENTRIES[3].name[0] == 'a'; |
|
| 57 | + | ||
| 58 | + | return 0; |
|
| 59 | + | } |