react_compiler_inference/
analyse_functions.rs1use indexmap::IndexMap;
16use react_compiler_diagnostics::{CompilerDiagnostic, ErrorCategory};
17use react_compiler_hir::environment::Environment;
18use std::collections::HashSet;
19
20use react_compiler_hir::{
21 AliasingEffect, BlockId, Effect, EvaluationOrder, FunctionId, HirFunction, IdentifierId,
22 InstructionValue, Place, ReactFunctionType, HIR,
23};
24
25pub fn analyse_functions<F>(func: &mut HirFunction, env: &mut Environment, debug_logger: &mut F) -> Result<(), CompilerDiagnostic>
37where
38 F: FnMut(&HirFunction, &Environment),
39{
40 let mut inner_func_ids: Vec<FunctionId> = Vec::new();
43 for (_block_id, block) in &func.body.blocks {
44 for instr_id in &block.instructions {
45 let instr = &func.instructions[instr_id.0 as usize];
46 match &instr.value {
47 InstructionValue::FunctionExpression { lowered_func, .. }
48 | InstructionValue::ObjectMethod { lowered_func, .. } => {
49 inner_func_ids.push(lowered_func.func);
50 }
51 _ => {}
52 }
53 }
54 }
55
56 for func_id in inner_func_ids {
58 let mut inner_func = std::mem::replace(
60 &mut env.functions[func_id.0 as usize],
61 placeholder_function(),
62 );
63
64 lower_with_mutation_aliasing(&mut inner_func, env, debug_logger)?;
65
66 if env.has_invariant_errors() {
68 env.functions[func_id.0 as usize] = inner_func;
69 return Ok(());
70 }
71
72 for operand in &inner_func.context {
79 let new_range = env.new_mutable_range(EvaluationOrder(0), EvaluationOrder(0));
80 let ident = &mut env.identifiers[operand.identifier.0 as usize];
81 ident.mutable_range = new_range;
82 ident.scope = None;
83 }
84
85 env.functions[func_id.0 as usize] = inner_func;
87 }
88
89 Ok(())
90}
91
92fn lower_with_mutation_aliasing<F>(func: &mut HirFunction, env: &mut Environment, debug_logger: &mut F) -> Result<(), CompilerDiagnostic>
96where
97 F: FnMut(&HirFunction, &Environment),
98{
99 analyse_functions(func, env, debug_logger)?;
101
102 crate::infer_mutation_aliasing_effects::infer_mutation_aliasing_effects(
104 func, env, true,
105 )?;
106
107 if env.has_invariant_errors() {
111 return Ok(());
112 }
113
114 react_compiler_optimization::dead_code_elimination(func, env);
116
117 let function_effects = crate::infer_mutation_aliasing_ranges::infer_mutation_aliasing_ranges(
119 func, env, true,
120 )?;
121
122 if let Err(err) = react_compiler_ssa::rewrite_instruction_kinds_based_on_reassignment(func, env) {
124 env.errors.merge(err);
125 return Ok(());
126 }
127
128 crate::infer_reactive_scope_variables::infer_reactive_scope_variables(func, env)?;
130
131 func.aliasing_effects = Some(function_effects.clone());
132
133 let mut captured_or_mutated: HashSet<IdentifierId> = HashSet::new();
136 for effect in &function_effects {
137 match effect {
138 AliasingEffect::Assign { from, .. }
139 | AliasingEffect::Alias { from, .. }
140 | AliasingEffect::Capture { from, .. }
141 | AliasingEffect::CreateFrom { from, .. }
142 | AliasingEffect::MaybeAlias { from, .. } => {
143 captured_or_mutated.insert(from.identifier);
144 }
145 AliasingEffect::Mutate { value, .. }
146 | AliasingEffect::MutateConditionally { value }
147 | AliasingEffect::MutateTransitive { value }
148 | AliasingEffect::MutateTransitiveConditionally { value } => {
149 captured_or_mutated.insert(value.identifier);
150 }
151 AliasingEffect::Impure { .. }
152 | AliasingEffect::Render { .. }
153 | AliasingEffect::MutateFrozen { .. }
154 | AliasingEffect::MutateGlobal { .. }
155 | AliasingEffect::CreateFunction { .. }
156 | AliasingEffect::Create { .. }
157 | AliasingEffect::Freeze { .. }
158 | AliasingEffect::ImmutableCapture { .. } => {
159 }
161 AliasingEffect::Apply { .. } => {
162 return Err(CompilerDiagnostic::new(
163 ErrorCategory::Invariant,
164 "[AnalyzeFunctions] Expected Apply effects to be replaced with more precise effects",
165 None,
166 ));
167 }
168 }
169 }
170
171 for operand in &mut func.context {
172 if captured_or_mutated.contains(&operand.identifier)
173 || operand.effect == Effect::Capture
174 {
175 operand.effect = Effect::Capture;
176 } else {
177 operand.effect = Effect::Read;
178 }
179 }
180
181 debug_logger(func, env);
183
184 Ok(())
185}
186
187
188fn placeholder_function() -> HirFunction {
192 HirFunction {
193 loc: None,
194 id: None,
195 name_hint: None,
196 fn_type: ReactFunctionType::Other,
197 params: Vec::new(),
198 return_type_annotation: None,
199 returns: Place {
200 identifier: IdentifierId(0),
201 effect: Effect::Unknown,
202 reactive: false,
203 loc: None,
204 },
205 context: Vec::new(),
206 body: HIR {
207 entry: BlockId(0),
208 blocks: IndexMap::new(),
209 },
210 instructions: Vec::new(),
211 generator: false,
212 is_async: false,
213 directives: Vec::new(),
214 aliasing_effects: None,
215 }
216}