Skip to main content

luaur_analysis/methods/
cfg_builder_emit_refine_instruction.rs

1//! Source: `Analysis/src/ControlFlowGraph.cpp:424-462` (hand-ported)
2//! C++ `void CFGBuilder::emitRefineInstruction(Block* block, RefinementId refinement)`.
3use crate::methods::refinement_arena_type_proposition::refinement_arena_type_proposition;
4use crate::records::block::Block;
5use crate::records::cfg_builder::CfgBuilder;
6use crate::records::proposition_control_flow_graph::Proposition;
7use crate::records::refine::Refine;
8use crate::type_aliases::def_id_control_flow_graph::DefId;
9use crate::type_aliases::refinement_control_flow_graph::{Refinement, RefinementMember};
10use crate::type_aliases::refinement_id_control_flow_graph::RefinementId;
11use luaur_common::macros::luau_assert::LUAU_ASSERT;
12
13impl CfgBuilder {
14    pub fn emit_refine_instruction(&mut self, block: *mut Block, refinement: RefinementId) {
15        // C++ `Luau::visit(overloaded{...}, *refinement)` over the 4 variant kinds.
16        // Scalar fields are copied out of the borrow before mutating `self`.
17        let variant_index = unsafe { (*refinement).index() };
18
19        match variant_index {
20            // Proposition (variant index 3)
21            3 => {
22                let prop: &Proposition =
23                    <Proposition as RefinementMember>::get_if(unsafe { &*refinement }).unwrap();
24                // DefId refined = newDefinition(prop.ptr->sym);
25                let ptr = prop.ptr;
26                let sym = unsafe { (*ptr).sym.clone() };
27                let refined: DefId = self.new_definition(sym.clone());
28                // emit<Refine>(block, refined, refinement);
29                self.emit::<Refine, _>(block, (refined, refinement as *const Refinement));
30                // block->setReachingDefinition(prop.ptr->sym, refined);
31                unsafe { (*block).set_reaching_definition(sym, refined) };
32            }
33            // Conjunction (variant index 0)
34            0 => {
35                use crate::records::conjunction_control_flow_graph::Conjunction;
36                let conj: &Conjunction =
37                    <Conjunction as RefinementMember>::get_if(unsafe { &*refinement }).unwrap();
38                let (lhs, rhs) = (conj.lhs, conj.rhs);
39                // emitRefineInstruction(block, conj.lhs); emitRefineInstruction(block, conj.rhs);
40                self.emit_refine_instruction(block, lhs);
41                self.emit_refine_instruction(block, rhs);
42            }
43            // Negation (variant index 2)
44            2 => {
45                use crate::records::negation_control_flow_graph::Negation;
46                let neg: &Negation =
47                    <Negation as RefinementMember>::get_if(unsafe { &*refinement }).unwrap();
48                // RefinementArena::negation pushes through And/Or via DeMorgan and cancels
49                // double negation, so the only shape that reaches here is Negation(Proposition).
50                // auto prop = neg.refinement->get_if<Proposition>();
51                let prop_ref = unsafe { &*neg.refinement };
52                let prop = <Proposition as RefinementMember>::get_if(prop_ref);
53                // LUAU_ASSERT(prop != nullptr);
54                LUAU_ASSERT!(prop.is_some());
55                let prop = prop.unwrap();
56                let (p_ptr, p_type, p_is_typeof, p_sense) =
57                    (prop.ptr, prop.r#type.clone(), prop.is_typeof, prop.sense);
58                // emitRefineInstruction(block, allocator->refinementArena.typeProposition(
59                //     prop->ptr, prop->type, prop->isTypeof, !prop->sense));
60                let fresh = {
61                    let arena = unsafe { &mut (*self.allocator).refinement_arena };
62                    refinement_arena_type_proposition(arena, p_ptr, p_type, p_is_typeof, !p_sense)
63                };
64                self.emit_refine_instruction(block, fresh);
65            }
66            // Disjunction (variant index 1)
67            // CLI-205330 tracks the work needed to handle Disjunctions; no-op for now.
68            _ => {}
69        }
70    }
71}