Skip to main content

react_compiler_hir/
reactive.rs

1// Copyright (c) Meta Platforms, Inc. and affiliates.
2//
3// This source code is licensed under the MIT license found in the
4// LICENSE file in the root directory of this source tree.
5
6//! Reactive function types — tree representation of a compiled function.
7//!
8//! `ReactiveFunction` is derived from the HIR CFG by `BuildReactiveFunction`.
9//! Control flow constructs (if/switch/loops/try) and reactive scopes become
10//! nested blocks rather than block references.
11//!
12//! Corresponds to the reactive types in `HIR.ts`.
13
14use react_compiler_diagnostics::SourceLocation;
15
16use crate::{
17    AliasingEffect, BlockId, EvaluationOrder, InstructionValue, LogicalOperator, ParamPattern,
18    Place, ScopeId,
19};
20
21// =============================================================================
22// ReactiveFunction
23// =============================================================================
24
25/// Tree representation of a compiled function, converted from the CFG-based HIR.
26/// TS: ReactiveFunction in HIR.ts
27#[derive(Debug, Clone)]
28pub struct ReactiveFunction {
29    pub loc: Option<SourceLocation>,
30    pub id: Option<String>,
31    pub name_hint: Option<String>,
32    pub params: Vec<ParamPattern>,
33    pub generator: bool,
34    pub is_async: bool,
35    pub body: ReactiveBlock,
36    pub directives: Vec<String>,
37    // No env field — passed separately per established Rust convention
38}
39
40// =============================================================================
41// ReactiveBlock and ReactiveStatement
42// =============================================================================
43
44/// TS: ReactiveBlock = Array<ReactiveStatement>
45pub type ReactiveBlock = Vec<ReactiveStatement>;
46
47/// TS: ReactiveStatement (discriminated union with 'kind' field)
48#[derive(Debug, Clone)]
49pub enum ReactiveStatement {
50    Instruction(ReactiveInstruction),
51    Terminal(ReactiveTerminalStatement),
52    Scope(ReactiveScopeBlock),
53    PrunedScope(PrunedReactiveScopeBlock),
54}
55
56// =============================================================================
57// ReactiveInstruction and ReactiveValue
58// =============================================================================
59
60/// TS: ReactiveInstruction
61#[derive(Debug, Clone)]
62pub struct ReactiveInstruction {
63    pub id: EvaluationOrder,
64    pub lvalue: Option<Place>,
65    pub value: ReactiveValue,
66    pub effects: Option<Vec<AliasingEffect>>,
67    pub loc: Option<SourceLocation>,
68}
69
70/// Extends InstructionValue with compound expression types that were
71/// separate blocks+terminals in HIR but become nested expressions here.
72/// TS: ReactiveValue = InstructionValue | ReactiveLogicalValue | ...
73#[derive(Debug, Clone)]
74pub enum ReactiveValue {
75    /// All ~35 base instruction value kinds
76    Instruction(InstructionValue),
77
78    /// TS: ReactiveLogicalValue
79    LogicalExpression {
80        operator: LogicalOperator,
81        left: Box<ReactiveValue>,
82        right: Box<ReactiveValue>,
83        loc: Option<SourceLocation>,
84    },
85
86    /// TS: ReactiveTernaryValue
87    ConditionalExpression {
88        test: Box<ReactiveValue>,
89        consequent: Box<ReactiveValue>,
90        alternate: Box<ReactiveValue>,
91        loc: Option<SourceLocation>,
92    },
93
94    /// TS: ReactiveSequenceValue
95    SequenceExpression {
96        instructions: Vec<ReactiveInstruction>,
97        id: EvaluationOrder,
98        value: Box<ReactiveValue>,
99        loc: Option<SourceLocation>,
100    },
101
102    /// TS: ReactiveOptionalCallValue
103    OptionalExpression {
104        id: EvaluationOrder,
105        value: Box<ReactiveValue>,
106        optional: bool,
107        loc: Option<SourceLocation>,
108    },
109}
110
111// =============================================================================
112// Terminals
113// =============================================================================
114
115#[derive(Debug, Clone)]
116pub struct ReactiveTerminalStatement {
117    pub terminal: ReactiveTerminal,
118    pub label: Option<ReactiveLabel>,
119}
120
121#[derive(Debug, Clone)]
122pub struct ReactiveLabel {
123    pub id: BlockId,
124    pub implicit: bool,
125}
126
127#[derive(Debug, Clone, PartialEq, Eq)]
128pub enum ReactiveTerminalTargetKind {
129    Implicit,
130    Labeled,
131    Unlabeled,
132}
133
134impl std::fmt::Display for ReactiveTerminalTargetKind {
135    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136        match self {
137            ReactiveTerminalTargetKind::Implicit => write!(f, "implicit"),
138            ReactiveTerminalTargetKind::Labeled => write!(f, "labeled"),
139            ReactiveTerminalTargetKind::Unlabeled => write!(f, "unlabeled"),
140        }
141    }
142}
143
144#[derive(Debug, Clone)]
145pub enum ReactiveTerminal {
146    Break {
147        target: BlockId,
148        id: EvaluationOrder,
149        target_kind: ReactiveTerminalTargetKind,
150        loc: Option<SourceLocation>,
151    },
152    Continue {
153        target: BlockId,
154        id: EvaluationOrder,
155        target_kind: ReactiveTerminalTargetKind,
156        loc: Option<SourceLocation>,
157    },
158    Return {
159        value: Place,
160        id: EvaluationOrder,
161        loc: Option<SourceLocation>,
162    },
163    Throw {
164        value: Place,
165        id: EvaluationOrder,
166        loc: Option<SourceLocation>,
167    },
168    Switch {
169        test: Place,
170        cases: Vec<ReactiveSwitchCase>,
171        id: EvaluationOrder,
172        loc: Option<SourceLocation>,
173    },
174    DoWhile {
175        loop_block: ReactiveBlock,
176        test: ReactiveValue,
177        id: EvaluationOrder,
178        loc: Option<SourceLocation>,
179    },
180    While {
181        test: ReactiveValue,
182        loop_block: ReactiveBlock,
183        id: EvaluationOrder,
184        loc: Option<SourceLocation>,
185    },
186    For {
187        init: ReactiveValue,
188        test: ReactiveValue,
189        update: Option<ReactiveValue>,
190        loop_block: ReactiveBlock,
191        id: EvaluationOrder,
192        loc: Option<SourceLocation>,
193    },
194    ForOf {
195        init: ReactiveValue,
196        test: ReactiveValue,
197        loop_block: ReactiveBlock,
198        id: EvaluationOrder,
199        loc: Option<SourceLocation>,
200    },
201    ForIn {
202        init: ReactiveValue,
203        loop_block: ReactiveBlock,
204        id: EvaluationOrder,
205        loc: Option<SourceLocation>,
206    },
207    If {
208        test: Place,
209        consequent: ReactiveBlock,
210        alternate: Option<ReactiveBlock>,
211        id: EvaluationOrder,
212        loc: Option<SourceLocation>,
213    },
214    Label {
215        block: ReactiveBlock,
216        id: EvaluationOrder,
217        loc: Option<SourceLocation>,
218    },
219    Try {
220        block: ReactiveBlock,
221        handler_binding: Option<Place>,
222        handler: ReactiveBlock,
223        id: EvaluationOrder,
224        loc: Option<SourceLocation>,
225    },
226}
227
228#[derive(Debug, Clone)]
229pub struct ReactiveSwitchCase {
230    pub test: Option<Place>,
231    pub block: Option<ReactiveBlock>,
232}
233
234// =============================================================================
235// Scope Blocks
236// =============================================================================
237
238#[derive(Debug, Clone)]
239pub struct ReactiveScopeBlock {
240    pub scope: ScopeId,
241    pub instructions: ReactiveBlock,
242}
243
244#[derive(Debug, Clone)]
245pub struct PrunedReactiveScopeBlock {
246    pub scope: ScopeId,
247    pub instructions: ReactiveBlock,
248}