swamp_code_gen/
iter.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 crate::transformer::{Collection, Transformer, TransformerResult};
8use crate::FlagStateKind;
9use source_map_node::Node;
10use swamp_semantic::{Expression, VariableRef};
11use swamp_vm_isa::{InstructionPosition, MemoryOffset};
12use swamp_vm_types::types::{
13    pointer_type, u32_type, u8_type, BasicTypeKind, BasicTypeRef, Place, TypedRegister, VmType,
14};
15use swamp_vm_types::{MemoryLocation, PatchPosition};
16use tracing::error;
17
18impl CodeBuilder<'_> {
19    /// Generates code to iterate over a collection using a transformer (e.g., map, filter, `filter_map`)
20    /// and a lambda expression. Handles creation of result vectors, iterator setup, lambda invocation,
21    /// early exit logic, and result collection.
22    ///
23    /// Steps:
24    /// 1. (Optional) Initialize a target vector for the result, if the transformer produces one.
25    /// 2. Initialize the iterator for the collection.
26    /// 3. Generate code to fetch the next element from the iterator.
27    /// 4. Spill lambda variables to protect them from being clobbered by function calls
28    /// 5. Inline the lambda code for the current element.
29    /// 6. Restore lambda variables from stack after lambda execution
30    /// 7. If the transformer supports early exit (e.g., filter, find), set the P flag based on the lambda result.
31    /// 8. Conditionally skip result insertion if early exit is triggered.
32    /// 9. (Optional) If applicable, insert the (possibly unwrapped) result into the target vector.
33    /// 10. Loop back to fetch the next element.
34    /// 11. Finalize iteration, handling any post-processing (e.g., normalizing boolean results).
35    ///
36    /// # Parameters
37    /// - `node`: The AST node for error reporting and code location.
38    /// - `collection_type`: The type of collection being iterated.
39    /// - `transformer`: The transformer operation (map, filter, find, fold, etc.).
40    /// - `collection_self_region`: Memory region of the collection.
41    /// - `lambda_expression`: The lambda expression to apply.
42    /// - `ctx`: Code generation context. Contains the result target.
43    ///
44    /// # Returns
45    /// - `Ok(())` on success, or an error if code generation fails.
46    ///
47    /// # Errors
48    /// // TODO:
49    /// # Panics
50    /// - If the lambda expression or its kind is not as expected (internal error).
51    #[allow(clippy::too_many_lines)]
52    #[allow(clippy::too_many_arguments)]
53    pub fn emit_iterate_over_collection_with_lambda(
54        &mut self,
55        target_destination: &Place,
56        node: &Node,
57        source_collection_type: Collection,
58        transformer: Transformer,
59        source_collection_reg: &TypedRegister,
60        lambda_tuple: (Vec<VariableRef>, &Expression),
61        ctx: &Context,
62    ) {
63        let (lambda_variables, lambda_expr) = lambda_tuple;
64        let maybe_primary_element_gen_type = source_collection_reg.ty.basic_type.element();
65
66        let target_variables: Vec<_> = lambda_variables
67            .iter()
68            .map(|x| {
69                self.variable_registers
70                    .get(&x.unique_id_within_function)
71                    .unwrap()
72                    .clone()
73            })
74            .collect();
75
76        // Primary is the right most variable
77        let primary_variable = &target_variables[target_variables.len() - 1];
78
79
80        let hwm = self.temp_registers.save_mark();
81
82
83        let temp_index_reg_for_mut_source = match transformer.return_type() {
84            TransformerResult::VecMutateSourceCollection => {
85                let temp_reg = self.temp_registers.allocate(VmType::new_contained_in_register(u32_type()), "mutate index");
86                self.builder.add_mov_32_immediate_value(temp_reg.register(), 0, node, "initialize index register to zero");
87                Some(temp_reg.register().clone())
88            }
89            _ => None
90        };
91
92        // 1. Initialize the target collection if needed and compute collection pointer
93        let maybe_target_collection_pointer = match transformer.return_type() {
94            TransformerResult::VecFromSourceCollection | TransformerResult::VecWithLambdaResult => {
95                // For transformers that create collections (filter, map, filterMap),
96                // we need to initialize the target vector before adding elements
97                let target_memory_location = target_destination.memory_location_or_pointer_reg();
98
99                self.emit_initialize_memory_for_any_type(
100                    &target_memory_location,
101                    node,
102                    "initialize target collection for transformer",
103                );
104
105                // For VecFromSourceCollection, compute the collection pointer now to avoid
106                // it being clobbered during lambda execution
107                if matches!(
108                    transformer.return_type(),
109                    TransformerResult::VecFromSourceCollection
110                ) {
111                    let computed_pointer = self.emit_compute_effective_address_to_register(
112                        target_destination,
113                        node,
114                        "get pointer to collection (before lambda execution)",
115                    );
116
117                    Some(computed_pointer)
118                } else {
119                    None
120                }
121            }
122            _ => {
123                // Other transformers don't need target initialization
124                None
125            }
126        };
127
128        // 2. Initialize the iterator and generate code to fetch the next element.
129        let (continue_iteration_label, iteration_complete_patch_position) = self
130            .emit_iter_init_and_next(
131                node,
132                source_collection_type,
133                maybe_primary_element_gen_type,
134                source_collection_reg,
135                &target_variables,
136            );
137
138        // 3. Inline the lambda code for the current element(s).
139        let lambda_result = self.emit_scalar_rvalue(lambda_expr, ctx);
140
141        // 4. If the transformer supports early exit, set the P flag based on the lambda result.
142        let transformer_t_flag_state = self.check_if_transformer_sets_t_flag(transformer);
143
144        // 5. Conditionally skip result insertion if early exit is triggered.
145        let maybe_skip_early = if self.check_if_transformer_can_skip_early(transformer)
146            && matches!(
147                transformer_t_flag_state,
148                FlagStateKind::TFlagIsTrueWhenSet | FlagStateKind::TFlagIsTrueWhenClear
149            ) {
150            let skip_early = match transformer.return_type() {
151                TransformerResult::WrappedValueFromSourceCollection => {
152                    let skip_over_some_section = self.builder.add_jmp_if_not_true_placeholder(
153                        &lambda_result,
154                        node,
155                        "skip over setting Some section",
156                    );
157
158                    let destination_type = target_destination.ty();
159                    let BasicTypeKind::Optional(tagged_union) = &destination_type.kind else {
160                        panic!("expected optional {destination_type:?}");
161                    };
162
163                    let tag_some_value_reg = self.temp_registers.allocate(
164                        VmType::new_unknown_placement(u8_type()),
165                        "iterate over collection target",
166                    );
167
168                    self.builder.add_mov8_immediate(
169                        tag_some_value_reg.register(),
170                        1,
171                        node,
172                        "mark tag as Some",
173                    );
174
175                    let result_location = target_destination.memory_location_or_pointer_reg();
176
177                    self.builder.add_st8_using_ptr_with_offset(
178                        &result_location.unsafe_add_offset(tagged_union.tag_offset),
179                        tag_some_value_reg.register(),
180                        node,
181                        "store Tag value of (1) into memory",
182                    );
183
184                    // TODO: let payload_memory_location = result_location.unsafe_add_offset(tagged_union.payload_offset);
185                    let payload_memory_location = result_location.unsafe_add_offset(MemoryOffset(4));
186                    let payload_destination = Place::Memory(payload_memory_location);
187
188                    let source_location = Place::Register(primary_variable.clone());
189
190                    self.emit_store_value_to_memory_place(
191                        &payload_destination,
192                        &source_location,
193                        node,
194                        "copy result in place",
195                    );
196
197                    // The P flag is set so we can act on it
198                    let skip_early = self.builder.add_jump_placeholder(
199                        node,
200                        "skip early",
201                    );
202
203
204                    self.builder.patch_jump_here(skip_over_some_section);
205
206                    skip_early
207                }
208                _ => {
209                    // The P flag is set so we can act on it
210                    self.builder.add_jmp_if_not_equal_polarity_placeholder(
211                        &lambda_result,
212                        &transformer_t_flag_state.polarity(),
213                        node,
214                        "skip early",
215                    )
216                }
217            };
218
219
220            Some(skip_early)
221        } else {
222            // P flag is not set, we have to iterate through the whole collection
223            None
224        };
225
226        // 6. If applicable, insert the (possibly unwrapped) result into the target vector.
227
228        match transformer.return_type() {
229            TransformerResult::Unit => {
230
231                // Only alternative is that it is a bool return, so no need to take any action here
232            }
233            TransformerResult::Bool => {
234                // Only alternative is that it is a bool return, so no need to take any action here
235            }
236            TransformerResult::WrappedValueFromSourceCollection => {
237                // Handled elsewhere
238            }
239            TransformerResult::VecWithLambdaResult => {
240                self.transformer_add_to_collection(
241                    &lambda_result,
242                    transformer.needs_tag_removed(),
243                    source_collection_type,
244                    target_destination.register().unwrap(),
245                    node,
246                );
247            }
248            TransformerResult::VecFromSourceCollection => {
249                let skip_if_false_patch_position = self.builder.add_jmp_if_not_true_placeholder(
250                    &lambda_result,
251                    node,
252                    "skip the result if it is false",
253                );
254
255                let absolute_pointer = maybe_target_collection_pointer
256                    .as_ref()
257                    .expect("collection pointer should have been computed before lambda execution");
258
259                self.add_to_collection(
260                    node,
261                    source_collection_type,
262                    absolute_pointer,
263                    primary_variable,
264                );
265
266                self.builder.patch_jump_here(skip_if_false_patch_position);
267            }
268
269            TransformerResult::VecMutateSourceCollection => {
270                let skip_if_false_patch_position = self.builder.add_jmp_if_not_true_placeholder(
271                    &lambda_result,
272                    node,
273                    "skip the result if it is false",
274                );
275
276                // TODO: have a subscript index and overwrite
277                let index_reg = temp_index_reg_for_mut_source.unwrap();
278                let pointer_to_entry_reg = self.temp_registers.allocate(VmType::new_contained_in_register(pointer_type()), "holds pointer to vec entry");
279                self.builder.add_vec_subscript(pointer_to_entry_reg.register(), source_collection_reg, &index_reg, node, "get pointer to element");
280
281
282                self.builder.patch_jump_here(skip_if_false_patch_position);
283            }
284        }
285
286        // 7. Loop back to fetch the next element.
287        self.builder.add_jmp(
288            continue_iteration_label,
289            &lambda_expr.debug_last_expression().node,
290            "jump to iter_next",
291        );
292
293        self.builder
294            .patch_jump_here(iteration_complete_patch_position);
295
296        if let Some(found_skip_early) = maybe_skip_early {
297            self.builder.patch_jump_here(found_skip_early);
298        }
299
300
301        self.temp_registers.restore_to_mark(hwm);
302    }
303
304    #[allow(clippy::unnecessary_wraps)]
305    #[allow(clippy::too_many_lines)]
306    fn emit_iter_init_and_next(
307        &mut self,
308        node: &Node,
309        collection_type: Collection,
310        maybe_element_type: Option<BasicTypeRef>,
311        collection_self_addr: &TypedRegister,
312        target_variables: &[TypedRegister],
313    ) -> (InstructionPosition, PatchPosition) {
314        let iterator_gen_type = collection_type.iterator_gen_type();
315
316        let target_iterator_header_reg = self.allocate_frame_space_and_return_absolute_pointer_reg(
317            &iterator_gen_type,
318            false,
319            node,
320            "allocate iterator header space",
321        );
322
323        let primary_register = if target_variables.len() == 2 {
324            &target_variables[1]
325        } else {
326            &target_variables[0]
327        };
328
329        let iter_next_position = InstructionPosition(self.builder.position().0 + 1);
330        let placeholder = match collection_type {
331            Collection::Range => {
332                self.builder.add_range_iter_init(
333                    &target_iterator_header_reg,
334                    collection_self_addr,
335                    node,
336                    "range init",
337                );
338
339                assert_eq!(target_variables.len(), 1);
340                self.builder.add_range_iter_next_placeholder(
341                    &target_iterator_header_reg,
342                    &target_variables[0],
343                    node,
344                    "range iter next single",
345                )
346            }
347
348            Collection::Map => {
349                // For maps, we need to handle both key and value potentially being scalars
350                // Map iteration returns pointers to both key and value, so we need to load scalar values
351                // TODO: Clean this up a bit to be more easy to read
352                // TODO: Also, scalar values that are mutated should be stored back to the value register
353                // Keys are by design not allowed to be mutated in iteration.
354                let (temp_registers, target_variables_to_use) = if target_variables.len() == 2 {
355                    // Map iteration with key-value pairs
356                    let key_register = &target_variables[0];
357                    let value_register = &target_variables[1];
358
359                    let (key_is_scalar, value_is_scalar) =
360                        match &collection_self_addr.ty.basic_type.kind {
361                            BasicTypeKind::MapStorage {
362                                key_type,
363                                value_type,
364                                ..
365                            } => (key_type.is_scalar(), value_type.is_scalar()),
366                            BasicTypeKind::DynamicLengthMapView(key_item, value_item) => {
367                                (key_item.ty.is_scalar(), value_item.ty.is_scalar())
368                            }
369                            _ => (false, false),
370                        };
371
372                    let mut temp_regs = Vec::new();
373                    let mut target_vars = Vec::new();
374
375                    // Handle key
376                    if key_is_scalar {
377                        let temp_key_addr = self
378                            .temp_registers
379                            .allocate(key_register.ty.clone(), "temp address for key");
380                        temp_regs.push((temp_key_addr.register().clone(), key_register.clone()));
381                        target_vars.push(temp_key_addr.register);
382                    } else {
383                        target_vars.push(key_register.clone());
384                    }
385
386                    // Handle value
387                    if value_is_scalar {
388                        let temp_value_addr = self
389                            .temp_registers
390                            .allocate(value_register.ty.clone(), "temp address for value");
391                        temp_regs
392                            .push((temp_value_addr.register().clone(), value_register.clone()));
393                        target_vars.push(temp_value_addr.register);
394                    } else {
395                        target_vars.push(value_register.clone());
396                    }
397
398                    (Some(temp_regs), target_vars)
399                } else {
400                    // Single value iteration (values only)
401                    let value_register = &target_variables[0];
402                    let value_is_scalar = match &collection_self_addr.ty.basic_type.kind {
403                        BasicTypeKind::MapStorage { value_type, .. } => value_type.is_scalar(),
404                        BasicTypeKind::DynamicLengthMapView(_, value_item) => {
405                            value_item.ty.is_scalar()
406                        }
407                        _ => false,
408                    };
409
410                    if value_is_scalar {
411                        let temp_value_addr = self
412                            .temp_registers
413                            .allocate(value_register.ty.clone(), "temp address for value");
414                        (
415                            Some(vec![(
416                                temp_value_addr.register().clone(),
417                                value_register.clone(),
418                            )]),
419                            vec![temp_value_addr.register.clone()],
420                        )
421                    } else {
422                        (None, target_variables.to_vec())
423                    }
424                };
425
426                let patch_position = self.emit_iter_init_and_next_to_memory(
427                    &target_iterator_header_reg,
428                    node,
429                    collection_type,
430                    maybe_element_type,
431                    collection_self_addr,
432                    &target_variables_to_use,
433                );
434
435                // Load scalar values from the addresses returned by the map iterator
436                if let Some(temp_regs) = temp_registers {
437                    for (temp_addr_reg, target_scalar_reg) in temp_regs {
438                        let source_memory_location =
439                            MemoryLocation::new_copy_over_whole_type_with_zero_offset(
440                                temp_addr_reg,
441                            );
442                        self.emit_load_value_from_memory_source(
443                            &target_scalar_reg,
444                            &source_memory_location,
445                            node,
446                            "load scalar value from map iterator address",
447                        );
448                    }
449                }
450
451                patch_position
452            }
453            _ => {
454                let (temp_registers, target_variables_to_use) =
455                    if primary_register.ty.basic_type.is_scalar() {
456                        // For primitives, create temp register to hold the address, since they do not want
457                        // the address
458                        let temp_addr = self.temp_registers.allocate(
459                            VmType::new_contained_in_register(pointer_type()),
460                            "temp address for value",
461                        );
462
463                        if target_variables.len() == 2 {
464                            (
465                                Some(temp_addr.register().clone()),
466                                vec![target_variables[0].clone(), temp_addr.register.clone()],
467                            )
468                        } else {
469                            (
470                                Some(temp_addr.register().clone()),
471                                vec![temp_addr.register.clone()],
472                            )
473                        }
474                    } else {
475                        (None, target_variables.to_vec())
476                    };
477
478                let patch_position = self.emit_iter_init_and_next_to_memory(
479                    &target_iterator_header_reg,
480                    node,
481                    collection_type,
482                    maybe_element_type,
483                    collection_self_addr,
484                    &target_variables_to_use,
485                );
486
487                if let Some(temp_regs) = temp_registers {
488                    if collection_type == Collection::String {
489                        self.builder.add_mov_reg(
490                            primary_register,
491                            &temp_regs,
492                            node,
493                            "copy from temporary to primary scalar register",
494                        );
495                        //self.emit_copy_register(&temp_regs, primary_register, node, "comment");
496                    } else {
497                        let source_memory_location =
498                            MemoryLocation::new_copy_over_whole_type_with_zero_offset(temp_regs);
499                        self.emit_load_value_from_memory_source(
500                            primary_register,
501                            &source_memory_location,
502                            node,
503                            "load primitive from element address",
504                        );
505                    }
506                }
507
508                patch_position
509            }
510        };
511
512        (iter_next_position, placeholder)
513    }
514
515    fn emit_iter_init_and_next_to_memory(
516        &mut self,
517        target_iterator_header_reg: &TypedRegister,
518        node: &Node,
519        collection_type: Collection,
520        maybe_element_type: Option<BasicTypeRef>,
521        collection_self_addr: &TypedRegister,
522        target_variables: &[TypedRegister],
523    ) -> PatchPosition {
524        let primary_register = if target_variables.len() == 2 {
525            &target_variables[1]
526        } else {
527            &target_variables[0]
528        };
529        let is_pair = target_variables.len() == 2;
530        match collection_type {
531            // Low  prio
532            Collection::String => {
533                if maybe_element_type.is_none() {
534                    error!(
535                        ?collection_self_addr,
536                        "can no start iterating with this strange vec collection"
537                    );
538                }
539
540                self.builder.add_string_iter_init(
541                    target_iterator_header_reg,
542                    collection_self_addr,
543                    maybe_element_type.unwrap().total_size,
544                    node,
545                    "vec iter init",
546                );
547
548                let is_pair = target_variables.len() == 2;
549
550                if is_pair {
551                    // For non-primitives, use target directly
552                    self.builder.add_string_iter_next_pair_placeholder(
553                        target_iterator_header_reg,
554                        &target_variables[0],
555                        &target_variables[1],
556                        node,
557                        "vec iter next pair",
558                    )
559                } else {
560                    // For non-primitives, use target directly
561                    self.builder.add_string_iter_next_placeholder(
562                        target_iterator_header_reg,
563                        primary_register,
564                        node,
565                        "vec iter next single",
566                    )
567                }
568            }
569            Collection::Vec => {
570                if maybe_element_type.is_none() {
571                    error!(
572                        ?collection_self_addr,
573                        "can no start iterating with this strange vec collection"
574                    );
575                }
576
577                self.builder.add_vec_iter_init(
578                    target_iterator_header_reg,
579                    collection_self_addr,
580                    node,
581                    "vec iter init",
582                );
583
584                let is_pair = target_variables.len() == 2;
585
586                if is_pair {
587                    // For non-primitives, use target directly
588                    self.builder.add_vec_iter_next_pair_placeholder(
589                        target_iterator_header_reg,
590                        &target_variables[0],
591                        &target_variables[1],
592                        node,
593                        "vec iter next pair",
594                    )
595                } else {
596                    // For non-primitives, use target directly
597                    self.builder.add_vec_iter_next_placeholder(
598                        target_iterator_header_reg,
599                        primary_register,
600                        node,
601                        "vec iter next single",
602                    )
603                }
604            }
605            Collection::Sparse => {
606                self.builder.add_sparse_iter_init(
607                    target_iterator_header_reg,
608                    collection_self_addr,
609                    node,
610                    "sparse init",
611                );
612
613                if is_pair {
614                    self.builder.add_sparse_iter_next_pair_placeholder(
615                        target_iterator_header_reg,
616                        &target_variables[0],
617                        &target_variables[1],
618                        node,
619                        "sparse next_pair",
620                    )
621                } else {
622                    self.builder.add_sparse_iter_next_placeholder(
623                        target_iterator_header_reg,
624                        primary_register,
625                        node,
626                        "sparse next_single",
627                    )
628                }
629            }
630
631            Collection::Map => {
632                self.builder.add_map_iter_init(
633                    target_iterator_header_reg,
634                    collection_self_addr,
635                    node,
636                    "map init",
637                );
638
639                if target_variables.len() == 2 {
640                    self.builder.add_map_iter_next_pair_placeholder(
641                        target_iterator_header_reg,
642                        &target_variables[0],
643                        &target_variables[1],
644                        node,
645                        "map next_pair",
646                    )
647                } else {
648                    self.builder.add_map_iter_next_placeholder(
649                        target_iterator_header_reg,
650                        &target_variables[0],
651                        node,
652                        "map next_single",
653                    )
654                }
655            }
656            Collection::Grid => todo!(),
657            _ => panic!("unknown collection"),
658        }
659    }
660
661    const fn check_if_transformer_sets_t_flag(
662        &mut self,
663        transformer: Transformer,
664    ) -> FlagStateKind {
665        match transformer {
666            Transformer::For => FlagStateKind::TFlagIsIndeterminate,
667            Transformer::While => FlagStateKind::TFlagIsTrueWhenSet,
668            Transformer::Filter => {
669                // TODO: Bring this back //assert_eq!(in_value.size().0, 1); // bool
670                FlagStateKind::TFlagIsTrueWhenSet
671            }
672            Transformer::FilterMut => {
673                // TODO: Bring this back //assert_eq!(in_value.size().0, 1); // bool
674                FlagStateKind::TFlagIsTrueWhenSet
675            }
676            Transformer::Find => {
677                // TODO: Bring this back //assert_eq!(in_value.size().0, 1); // bool
678                FlagStateKind::TFlagIsTrueWhenClear
679            }
680            Transformer::Map => FlagStateKind::TFlagIsIndeterminate,
681            Transformer::Any => FlagStateKind::TFlagIsTrueWhenClear,
682            Transformer::All => FlagStateKind::TFlagIsTrueWhenSet,
683            Transformer::FilterMap => FlagStateKind::TFlagIsTrueWhenSet,
684        }
685    }
686
687    fn add_to_collection(
688        &mut self,
689        node: &Node,
690        collection: Collection,
691        mut_collection: &TypedRegister,
692        value: &TypedRegister,
693    ) {
694        match collection {
695            Collection::Vec => {
696                let target_element_addr_reg = self.temp_registers.allocate(
697                    VmType::new_contained_in_register(u32_type()),
698                    "address for the element entry",
699                );
700
701                self.builder.add_vec_push_addr(
702                    target_element_addr_reg.register(),
703                    mut_collection,
704                    node,
705                    "add_to_collection for transformer",
706                );
707
708                let vec_entry_destination =
709                    Place::Memory(MemoryLocation::new_copy_over_whole_type_with_zero_offset(
710                        target_element_addr_reg.register().clone(),
711                    ));
712
713                // Initialize the allocated space first (like variable definition)
714                if value.ty.basic_type.is_aggregate() {
715                    self.emit_initialize_memory_for_any_type(
716                        vec_entry_destination.grab_memory_location(),
717                        node,
718                        "initialize vec.push allocated space for transformer",
719                    );
720                }
721
722                let source_destination = if value.ty.is_scalar() {
723                    Place::Register(value.clone())
724                } else {
725                    Place::Memory(MemoryLocation::new_copy_over_whole_type_with_zero_offset(
726                        value.clone(),
727                    ))
728                };
729
730                self.emit_store_value_to_memory_place(
731                    &vec_entry_destination,
732                    &source_destination,
733                    node,
734                    "store value in the new vec entry slot",
735                );
736            }
737            Collection::Sparse => panic!("not supported by sparse"),
738            Collection::Map => todo!(),
739            Collection::Grid => todo!(),
740            Collection::String => todo!(),
741            Collection::Range => todo!(),
742        }
743    }
744
745    fn transformer_add_to_collection(
746        &mut self,
747        in_value: &TypedRegister,
748        should_unwrap_value: bool,
749        collection_type: Collection,
750        mut_collection: &TypedRegister,
751        node: &Node,
752    ) {
753        let (register_to_be_inserted_in_collection, _maybe_temp) = if should_unwrap_value {
754            let tagged_union = in_value.underlying().optional_info().unwrap().clone();
755            let some_variant = tagged_union.get_variant_by_index(1);
756            let payload_vm_type = VmType::new_unknown_placement(some_variant.ty.clone());
757            let temp_reg = self
758                .temp_registers
759                .allocate(payload_vm_type, "transform add to collection");
760            let (_tag_offset, _tag_size, _payload_offset, _) =
761                in_value.underlying().unwrap_info().unwrap();
762
763            /*
764            in_value.unsafe_add_offset(payload_offset);
765
766            self.emit_load_from_memory_internal(
767                temp_reg.register(),
768                in_value,
769                payload_offset,
770                &payload_vm_type,
771                node,
772                "transformer add to collection",
773            );
774
775             */
776            (temp_reg.register.clone(), Some(temp_reg))
777        } else {
778            (in_value.clone(), None)
779        };
780
781        self.add_to_collection(
782            node,
783            collection_type,
784            mut_collection,
785            &register_to_be_inserted_in_collection,
786        );
787    }
788
789    const fn check_if_transformer_can_skip_early(&self, transformer: Transformer) -> bool {
790        match transformer {
791            Transformer::For => false,
792            Transformer::Filter => false,
793            Transformer::FilterMut => false,
794            Transformer::Find => true,
795            Transformer::While => true,
796            Transformer::Map => false,
797            Transformer::Any => true,
798            Transformer::All => true,
799            Transformer::FilterMap => false,
800        }
801    }
802}