Skip to main content

luaur_analysis/methods/
cfg_builder_emit.rs

1//! Source: `Analysis/include/Luau/ControlFlowGraph.h:306-312` (hand-ported)
2//! C++ `template<typename T, typename... Args> NotNull<T> CFGBuilder::emit(Block* block, Args&&... args)`.
3use crate::records::assign::Assign;
4use crate::records::block::Block;
5use crate::records::cfg_builder::CfgBuilder;
6use crate::records::declare::Declare;
7use crate::records::join::Join;
8use crate::records::refine::Refine;
9use crate::type_aliases::def_id_control_flow_graph::DefId;
10use crate::type_aliases::instruction::{Instruction, InstructionMember};
11use crate::type_aliases::refinement_control_flow_graph::Refinement;
12use luaur_ast::records::ast_stat_assign::AstStatAssign;
13use luaur_ast::records::ast_stat_local::AstStatLocal;
14
15/// Bridges the C++ `T{args...}` variadic construction: maps each instruction
16/// type `T` and its constructor arg-pack to a built `Instruction` variant.
17/// (C++ `instructions.allocate(T{std::forward<Args>(args)...})`.)
18pub trait IntoInstruction<T> {
19    fn into_instruction(self) -> Instruction;
20}
21
22// emit<Declare>(block, (def, source)) -> Declare(def, source)
23impl IntoInstruction<Declare> for (DefId, *mut AstStatLocal) {
24    fn into_instruction(self) -> Instruction {
25        Instruction::Declare(Declare::declare(self.0, self.1))
26    }
27}
28
29// emit<Assign>(block, (def, source)) -> Assign(def, source)
30impl IntoInstruction<Assign> for (DefId, *mut AstStatAssign) {
31    fn into_instruction(self) -> Instruction {
32        Instruction::Assign(Assign::assign(self.0, self.1))
33    }
34}
35
36// emit<Join>(block, def) -> Join(definition)
37impl IntoInstruction<Join> for DefId {
38    fn into_instruction(self) -> Instruction {
39        // C++ `explicit Join(DefId definition)` — operands start empty.
40        Instruction::Join(Join {
41            definition: self,
42            operands: alloc::vec::Vec::new(),
43        })
44    }
45}
46
47// emit<Refine>(block, (definition, prop)) -> Refine(definition, prop)
48impl IntoInstruction<Refine> for (DefId, *const Refinement) {
49    fn into_instruction(self) -> Instruction {
50        Instruction::Refine(Refine {
51            definition: self.0,
52            prop: self.1,
53        })
54    }
55}
56
57impl CfgBuilder {
58    /// `template<typename T, typename... Args> NotNull<T> emit(Block* block, Args&&...)`.
59    /// `NotNull<T>` -> `*mut T`.
60    pub fn emit<T, Args>(&mut self, block: *mut Block, args: Args) -> *mut T
61    where
62        Args: IntoInstruction<T>,
63        T: InstructionMember,
64    {
65        // C++:
66        //   InstrId inst = allocator->newInstruction<T>(std::forward<Args>(args)...);
67        //   block->instructions.emplace_back(inst);
68        //   return NotNull{inst->template get_if<T>()};
69        let allocator = unsafe { &mut *self.allocator };
70        let inst = allocator.new_instruction(args.into_instruction());
71        unsafe {
72            (*block).instructions.push(inst);
73            <T as InstructionMember>::get_if_mut(&mut *inst).unwrap() as *mut T
74        }
75    }
76}