swamp_code_gen/
enum_variants.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use crate::code_bld::CodeBuilder;
6use crate::ctx::Context;
7use source_map_node::Node;
8use swamp_semantic::EnumLiteralExpressions;
9use swamp_types::prelude::EnumVariantType;
10use swamp_types::{TypeKind, TypeRef};
11use swamp_vm_types::AggregateMemoryLocation;
12use swamp_vm_types::types::{BasicTypeKind, VmType, u8_type};
13
14impl CodeBuilder<'_> {
15    pub fn emit_enum_variant_to_memory_location(
16        &mut self,
17        target_memory_location: &AggregateMemoryLocation,
18        enum_type: &TypeRef,
19        variant_type: &EnumVariantType,
20        sorted_expressions: &EnumLiteralExpressions,
21        node: &Node,
22        ctx: &Context,
23    ) {
24        let variant_index = variant_type.common().container_index as usize;
25        let layout_gen_enum = self.state.layout_cache.layout(enum_type);
26        let BasicTypeKind::TaggedUnion(layout_enum) = &layout_gen_enum.kind else {
27            panic!("wrong")
28        };
29        let layout_variant = layout_enum.get_variant_by_index(variant_index);
30
31        let hwm = self.temp_registers.save_mark();
32
33        // Set the enum variant tag
34        let temp_payload_reg = self.temp_registers.allocate(
35            VmType::new_unknown_placement(layout_variant.ty.clone()),
36            "variant literal payload",
37        );
38
39        self.builder.add_mov8_immediate(
40            temp_payload_reg.register(),
41            variant_index as u8,
42            node,
43            &format!("enum variant `{}` tag", variant_type.common().assigned_name),
44        );
45
46        let tag_memory_location = target_memory_location.offset(layout_enum.tag_offset, u8_type());
47        self.builder.add_st8_using_ptr_with_offset(
48            &tag_memory_location.location,
49            temp_payload_reg.register(),
50            node,
51            &format!("put enum tag in place {tag_memory_location} <- {temp_payload_reg}"),
52        );
53
54        // Get payload memory location
55        let payload_basic_type = self.state.layout_cache.layout(&variant_type.payload_type);
56        let payload_memory_location =
57            target_memory_location.offset(layout_enum.payload_offset, payload_basic_type.clone());
58
59        // IMPORTANT: Initialize any collections in the payload before filling it
60        // This ensures Vec and other collections are properly initialized before copying
61        self.emit_initialize_collections_in_type(
62            &payload_memory_location,
63            &payload_basic_type,
64            node,
65            &format!(
66                "initialize collections in enum variant payload for {}",
67                variant_type.common().assigned_name
68            ),
69        );
70
71        // Now fill the payload with the actual values
72        match &*variant_type.payload_type.kind {
73            TypeKind::Unit => {}
74            TypeKind::Tuple(_) => {
75                let EnumLiteralExpressions::Tuple(tuple_expressions) = sorted_expressions else {
76                    panic!("internal error");
77                };
78                self.emit_tuple_literal_into_memory(
79                    &payload_memory_location,
80                    &variant_type.payload_type,
81                    tuple_expressions,
82                    ctx,
83                    node,
84                );
85            }
86            TypeKind::AnonymousStruct(_) => {
87                let EnumLiteralExpressions::Struct(sorted_field_expressions) = sorted_expressions
88                else {
89                    panic!("internal error");
90                };
91
92                self.emit_anonymous_struct_into_memory(
93                    &payload_memory_location,
94                    &variant_type.payload_type,
95                    sorted_field_expressions,
96                    node,
97                    ctx,
98                );
99            }
100            _ => {
101                // Handle direct payload types (like Int, String, etc.) for single-element variants
102                let EnumLiteralExpressions::Tuple(tuple_expressions) = sorted_expressions else {
103                    panic!("internal error: expected single element tuple for direct payload type");
104                };
105
106                assert!(
107                    (tuple_expressions.len() == 1),
108                    "internal error: direct payload type should have exactly one expression"
109                );
110
111                // For direct payload types, emit the single expression directly to the payload location
112                self.emit_expression_into_target_memory(
113                    &payload_memory_location.location,
114                    &tuple_expressions[0],
115                    &format!(
116                        "direct payload for enum variant {}",
117                        variant_type.common().assigned_name
118                    ),
119                    ctx,
120                );
121            }
122        }
123
124        self.temp_registers.restore_to_mark(hwm);
125    }
126}