Fix lowering of void union variant in constant

6d59132f5ff1fc6ab5aeb22087349fd934102d27eafb0e79b8d2309900c12d7c
Alexis Sellier committed ago 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 +
}