1use react_compiler_ast::scope::ScopeInfo;
12use react_compiler_diagnostics::CompilerError;
13use react_compiler_hir::ReactFunctionType;
14use react_compiler_hir::environment::Environment;
15use react_compiler_hir::environment::OutputMode;
16use react_compiler_hir::environment_config::EnvironmentConfig;
17use react_compiler_lowering::FunctionNode;
18
19use super::compile_result::CodegenFunction;
20use super::compile_result::CompilerErrorDetailInfo;
21use super::compile_result::CompilerErrorItemInfo;
22use super::compile_result::DebugLogEntry;
23use super::compile_result::LoggerPosition;
24use super::compile_result::LoggerSourceLocation;
25use super::compile_result::OutlinedFunction;
26use super::imports::ProgramContext;
27use super::plugin_options::CompilerOutputMode;
28use crate::debug_print;
29
30pub fn compile_fn(
36 func: &FunctionNode<'_>,
37 fn_name: Option<&str>,
38 scope_info: &ScopeInfo,
39 fn_type: ReactFunctionType,
40 mode: CompilerOutputMode,
41 env_config: &EnvironmentConfig,
42 context: &mut ProgramContext,
43) -> Result<CodegenFunction, CompilerError> {
44 let mut env = Environment::with_config(env_config.clone());
45 env.fn_type = fn_type;
46 env.output_mode = match mode {
47 CompilerOutputMode::Ssr => OutputMode::Ssr,
48 CompilerOutputMode::Client => OutputMode::Client,
49 CompilerOutputMode::Lint => OutputMode::Lint,
50 };
51 env.code = context.code.clone();
52 env.filename = context.filename.clone();
53 env.instrument_fn_name = context.instrument_fn_name.clone();
54 env.instrument_gating_name = context.instrument_gating_name.clone();
55 env.hook_guard_name = context.hook_guard_name.clone();
56 env.seed_uid_known_names(&context.known_referenced_names());
57
58 env.reference_node_ids = scope_info.ref_node_id_to_binding.keys().copied().collect();
59
60 context.timing.start("lower");
61 let mut hir = react_compiler_lowering::lower(func, fn_name, scope_info, &mut env)?;
62 context.timing.stop();
63
64 if !env.renames.is_empty() {
66 context.renames.extend(env.renames.iter().cloned());
67 }
68
69 if env.has_invariant_errors() {
74 return Err(env.take_invariant_errors());
75 }
76
77 if context.debug_enabled {
78 context.timing.start("debug_print:HIR");
79 let debug_hir = debug_print::debug_hir(&hir, &env);
80 context.log_debug(DebugLogEntry::new("HIR", debug_hir));
81 context.timing.stop();
82 }
83
84 context.timing.start("PruneMaybeThrows");
85 react_compiler_optimization::prune_maybe_throws(&mut hir, &mut env.functions)?;
86 context.timing.stop();
87
88 if context.debug_enabled {
89 context.timing.start("debug_print:PruneMaybeThrows");
90 let debug_prune = debug_print::debug_hir(&hir, &env);
91 context.log_debug(DebugLogEntry::new("PruneMaybeThrows", debug_prune));
92 context.timing.stop();
93 }
94
95 context.timing.start("ValidateContextVariableLValues");
96 react_compiler_validation::validate_context_variable_lvalues(&hir, &mut env)?;
97 if context.debug_enabled {
98 context.log_debug(DebugLogEntry::new(
99 "ValidateContextVariableLValues",
100 "ok".to_string(),
101 ));
102 }
103 context.timing.stop();
104
105 context.timing.start("ValidateUseMemo");
106 let void_memo_errors = react_compiler_validation::validate_use_memo(&hir, &mut env);
107 log_errors_as_events(&void_memo_errors, context);
108 if context.debug_enabled {
109 context.log_debug(DebugLogEntry::new("ValidateUseMemo", "ok".to_string()));
110 }
111 context.timing.stop();
112
113 context.timing.start("DropManualMemoization");
114 react_compiler_optimization::drop_manual_memoization(&mut hir, &mut env)?;
115 context.timing.stop();
116
117 if context.debug_enabled {
118 context.timing.start("debug_print:DropManualMemoization");
119 let debug_drop_memo = debug_print::debug_hir(&hir, &env);
120 context.log_debug(DebugLogEntry::new("DropManualMemoization", debug_drop_memo));
121 context.timing.stop();
122 }
123
124 context
125 .timing
126 .start("InlineImmediatelyInvokedFunctionExpressions");
127 react_compiler_optimization::inline_immediately_invoked_function_expressions(
128 &mut hir, &mut env,
129 );
130 context.timing.stop();
131
132 if context.debug_enabled {
133 context
134 .timing
135 .start("debug_print:InlineImmediatelyInvokedFunctionExpressions");
136 let debug_inline_iifes = debug_print::debug_hir(&hir, &env);
137 context.log_debug(DebugLogEntry::new(
138 "InlineImmediatelyInvokedFunctionExpressions",
139 debug_inline_iifes,
140 ));
141 context.timing.stop();
142 }
143
144 context.timing.start("MergeConsecutiveBlocks");
145 react_compiler_optimization::merge_consecutive_blocks::merge_consecutive_blocks(
146 &mut hir,
147 &mut env.functions,
148 );
149 context.timing.stop();
150
151 if context.debug_enabled {
152 context.timing.start("debug_print:MergeConsecutiveBlocks");
153 let debug_merge = debug_print::debug_hir(&hir, &env);
154 context.log_debug(DebugLogEntry::new("MergeConsecutiveBlocks", debug_merge));
155 context.timing.stop();
156 }
157
158 if context.debug_enabled {
160 context.log_debug(DebugLogEntry::new(
161 "AssertConsistentIdentifiers",
162 "ok".to_string(),
163 ));
164 }
165 if context.debug_enabled {
167 context.log_debug(DebugLogEntry::new(
168 "AssertTerminalSuccessorsExist",
169 "ok".to_string(),
170 ));
171 }
172
173 context.timing.start("EnterSSA");
174 react_compiler_ssa::enter_ssa(&mut hir, &mut env).map_err(|diag| {
175 let loc = diag.primary_location().cloned();
176 let mut err = CompilerError::new();
177 err.push_error_detail(react_compiler_diagnostics::CompilerErrorDetail {
178 category: diag.category,
179 reason: diag.reason,
180 description: diag.description,
181 loc,
182 suggestions: diag.suggestions,
183 });
184 err
185 })?;
186 context.timing.stop();
187
188 if context.debug_enabled {
189 context.timing.start("debug_print:SSA");
190 let debug_ssa = debug_print::debug_hir(&hir, &env);
191 context.log_debug(DebugLogEntry::new("SSA", debug_ssa));
192 context.timing.stop();
193 }
194
195 context.timing.start("EliminateRedundantPhi");
196 react_compiler_ssa::eliminate_redundant_phi(&mut hir, &mut env);
197 context.timing.stop();
198
199 if context.debug_enabled {
200 context.timing.start("debug_print:EliminateRedundantPhi");
201 let debug_eliminate_phi = debug_print::debug_hir(&hir, &env);
202 context.log_debug(DebugLogEntry::new(
203 "EliminateRedundantPhi",
204 debug_eliminate_phi,
205 ));
206 context.timing.stop();
207 }
208
209 if context.debug_enabled {
211 context.log_debug(DebugLogEntry::new(
212 "AssertConsistentIdentifiers",
213 "ok".to_string(),
214 ));
215 }
216
217 context.timing.start("ConstantPropagation");
218 react_compiler_optimization::constant_propagation(&mut hir, &mut env);
219 context.timing.stop();
220
221 if context.debug_enabled {
222 context.timing.start("debug_print:ConstantPropagation");
223 let debug_const_prop = debug_print::debug_hir(&hir, &env);
224 context.log_debug(DebugLogEntry::new("ConstantPropagation", debug_const_prop));
225 context.timing.stop();
226 }
227
228 context.timing.start("InferTypes");
229 react_compiler_typeinference::infer_types(&mut hir, &mut env)?;
230 context.timing.stop();
231
232 if context.debug_enabled {
233 context.timing.start("debug_print:InferTypes");
234 let debug_infer_types = debug_print::debug_hir(&hir, &env);
235 context.log_debug(DebugLogEntry::new("InferTypes", debug_infer_types));
236 context.timing.stop();
237 }
238
239 if env.enable_validations() {
240 if env.config.validate_hooks_usage {
241 context.timing.start("ValidateHooksUsage");
242 react_compiler_validation::validate_hooks_usage(&hir, &mut env)?;
243 if context.debug_enabled {
244 context.log_debug(DebugLogEntry::new("ValidateHooksUsage", "ok".to_string()));
245 }
246 context.timing.stop();
247 }
248
249 if env.config.validate_no_capitalized_calls.is_some() {
250 context.timing.start("ValidateNoCapitalizedCalls");
251 react_compiler_validation::validate_no_capitalized_calls(&hir, &mut env)?;
252 if context.debug_enabled {
253 context.log_debug(DebugLogEntry::new(
254 "ValidateNoCapitalizedCalls",
255 "ok".to_string(),
256 ));
257 }
258 context.timing.stop();
259 }
260 }
261
262 context.timing.start("OptimizePropsMethodCalls");
263 react_compiler_optimization::optimize_props_method_calls(&mut hir, &env);
264 context.timing.stop();
265
266 if context.debug_enabled {
267 context.timing.start("debug_print:OptimizePropsMethodCalls");
268 let debug_optimize_props = debug_print::debug_hir(&hir, &env);
269 context.log_debug(DebugLogEntry::new(
270 "OptimizePropsMethodCalls",
271 debug_optimize_props,
272 ));
273 context.timing.stop();
274 }
275
276 context.timing.start("AnalyseFunctions");
277 let mut inner_logs: Vec<String> = Vec::new();
278 let debug_inner = context.debug_enabled;
279 let analyse_result = react_compiler_inference::analyse_functions(
280 &mut hir,
281 &mut env,
282 &mut |inner_func, inner_env| {
283 if debug_inner {
284 inner_logs.push(debug_print::debug_hir(inner_func, inner_env));
285 }
286 },
287 );
288 context.timing.stop();
289
290 if context.debug_enabled {
292 for inner_log in inner_logs {
293 context.log_debug(DebugLogEntry::new("AnalyseFunction (inner)", inner_log));
294 }
295 }
296
297 analyse_result?;
298
299 if env.has_invariant_errors() {
300 return Err(env.take_invariant_errors());
301 }
302
303 if context.debug_enabled {
304 context.timing.start("debug_print:AnalyseFunctions");
305 let debug_analyse_functions = debug_print::debug_hir(&hir, &env);
306 context.log_debug(DebugLogEntry::new(
307 "AnalyseFunctions",
308 debug_analyse_functions,
309 ));
310 context.timing.stop();
311 }
312
313 context.timing.start("InferMutationAliasingEffects");
314 react_compiler_inference::infer_mutation_aliasing_effects(&mut hir, &mut env, false)?;
315 context.timing.stop();
316
317 if context.debug_enabled {
318 context
319 .timing
320 .start("debug_print:InferMutationAliasingEffects");
321 let debug_infer_effects = debug_print::debug_hir(&hir, &env);
322 context.log_debug(DebugLogEntry::new(
323 "InferMutationAliasingEffects",
324 debug_infer_effects,
325 ));
326 context.timing.stop();
327 }
328
329 if env.output_mode == OutputMode::Ssr {
330 context.timing.start("OptimizeForSSR");
331 react_compiler_optimization::optimize_for_ssr(&mut hir, &env);
332 context.timing.stop();
333
334 if context.debug_enabled {
335 context.timing.start("debug_print:OptimizeForSSR");
336 let debug_ssr = debug_print::debug_hir(&hir, &env);
337 context.log_debug(DebugLogEntry::new("OptimizeForSSR", debug_ssr));
338 context.timing.stop();
339 }
340 }
341
342 context.timing.start("DeadCodeElimination");
343 react_compiler_optimization::dead_code_elimination(&mut hir, &env);
344 context.timing.stop();
345
346 if context.debug_enabled {
347 context.timing.start("debug_print:DeadCodeElimination");
348 let debug_dce = debug_print::debug_hir(&hir, &env);
349 context.log_debug(DebugLogEntry::new("DeadCodeElimination", debug_dce));
350 context.timing.stop();
351 }
352
353 context.timing.start("PruneMaybeThrows2");
354 react_compiler_optimization::prune_maybe_throws(&mut hir, &mut env.functions)?;
355 context.timing.stop();
356
357 if context.debug_enabled {
358 context.timing.start("debug_print:PruneMaybeThrows2");
359 let debug_prune2 = debug_print::debug_hir(&hir, &env);
360 context.log_debug(DebugLogEntry::new("PruneMaybeThrows", debug_prune2));
361 context.timing.stop();
362 }
363
364 context.timing.start("InferMutationAliasingRanges");
365 react_compiler_inference::infer_mutation_aliasing_ranges(&mut hir, &mut env, false)?;
366 context.timing.stop();
367
368 if context.debug_enabled {
369 context
370 .timing
371 .start("debug_print:InferMutationAliasingRanges");
372 let debug_infer_ranges = debug_print::debug_hir(&hir, &env);
373 context.log_debug(DebugLogEntry::new(
374 "InferMutationAliasingRanges",
375 debug_infer_ranges,
376 ));
377 context.timing.stop();
378 }
379
380 if env.enable_validations() {
381 context
382 .timing
383 .start("ValidateLocalsNotReassignedAfterRender");
384 react_compiler_validation::validate_locals_not_reassigned_after_render(&hir, &mut env);
385 if context.debug_enabled {
386 context.log_debug(DebugLogEntry::new(
387 "ValidateLocalsNotReassignedAfterRender",
388 "ok".to_string(),
389 ));
390 }
391 context.timing.stop();
392
393 if env.config.validate_ref_access_during_render {
394 context.timing.start("ValidateNoRefAccessInRender");
395 react_compiler_validation::validate_no_ref_access_in_render(&hir, &mut env);
396 if context.debug_enabled {
397 context.log_debug(DebugLogEntry::new(
398 "ValidateNoRefAccessInRender",
399 "ok".to_string(),
400 ));
401 }
402 context.timing.stop();
403 }
404
405 if env.config.validate_no_set_state_in_render {
406 context.timing.start("ValidateNoSetStateInRender");
407 react_compiler_validation::validate_no_set_state_in_render(&hir, &mut env)?;
408 if context.debug_enabled {
409 context.log_debug(DebugLogEntry::new(
410 "ValidateNoSetStateInRender",
411 "ok".to_string(),
412 ));
413 }
414 context.timing.stop();
415 }
416
417 if env.config.validate_no_derived_computations_in_effects_exp
418 && env.output_mode == OutputMode::Lint
419 {
420 context
421 .timing
422 .start("ValidateNoDerivedComputationsInEffects");
423 let errors =
424 react_compiler_validation::validate_no_derived_computations_in_effects_exp(
425 &hir, &env,
426 )?;
427 log_errors_as_events(&errors, context);
428 if context.debug_enabled {
429 context.log_debug(DebugLogEntry::new(
430 "ValidateNoDerivedComputationsInEffects",
431 "ok".to_string(),
432 ));
433 }
434 context.timing.stop();
435 } else if env.config.validate_no_derived_computations_in_effects {
436 context
437 .timing
438 .start("ValidateNoDerivedComputationsInEffects");
439 react_compiler_validation::validate_no_derived_computations_in_effects(&hir, &mut env)?;
440 if context.debug_enabled {
441 context.log_debug(DebugLogEntry::new(
442 "ValidateNoDerivedComputationsInEffects",
443 "ok".to_string(),
444 ));
445 }
446 context.timing.stop();
447 }
448
449 if env.config.validate_no_set_state_in_effects && env.output_mode == OutputMode::Lint {
450 context.timing.start("ValidateNoSetStateInEffects");
451 let errors = react_compiler_validation::validate_no_set_state_in_effects(&hir, &env)?;
452 log_errors_as_events(&errors, context);
453 if context.debug_enabled {
454 context.log_debug(DebugLogEntry::new(
455 "ValidateNoSetStateInEffects",
456 "ok".to_string(),
457 ));
458 }
459 context.timing.stop();
460 }
461
462 if env.config.validate_no_jsx_in_try_statements && env.output_mode == OutputMode::Lint {
463 context.timing.start("ValidateNoJSXInTryStatement");
464 let errors = react_compiler_validation::validate_no_jsx_in_try_statement(&hir);
465 log_errors_as_events(&errors, context);
466 if context.debug_enabled {
467 context.log_debug(DebugLogEntry::new(
468 "ValidateNoJSXInTryStatement",
469 "ok".to_string(),
470 ));
471 }
472 context.timing.stop();
473 }
474
475 context
476 .timing
477 .start("ValidateNoFreezingKnownMutableFunctions");
478 react_compiler_validation::validate_no_freezing_known_mutable_functions(&hir, &mut env);
479 if context.debug_enabled {
480 context.log_debug(DebugLogEntry::new(
481 "ValidateNoFreezingKnownMutableFunctions",
482 "ok".to_string(),
483 ));
484 }
485 context.timing.stop();
486 }
487
488 context.timing.start("InferReactivePlaces");
489 react_compiler_inference::infer_reactive_places(&mut hir, &mut env)?;
490 context.timing.stop();
491
492 if context.debug_enabled {
493 context.timing.start("debug_print:InferReactivePlaces");
494 let debug_reactive_places = debug_print::debug_hir(&hir, &env);
495 context.log_debug(DebugLogEntry::new(
496 "InferReactivePlaces",
497 debug_reactive_places,
498 ));
499 context.timing.stop();
500 }
501
502 if env.enable_validations() {
503 context.timing.start("ValidateExhaustiveDependencies");
504 react_compiler_validation::validate_exhaustive_dependencies(&mut hir, &mut env)?;
505 if context.debug_enabled {
506 context.log_debug(DebugLogEntry::new(
507 "ValidateExhaustiveDependencies",
508 "ok".to_string(),
509 ));
510 }
511 context.timing.stop();
512 }
513
514 context
515 .timing
516 .start("RewriteInstructionKindsBasedOnReassignment");
517 react_compiler_ssa::rewrite_instruction_kinds_based_on_reassignment(&mut hir, &env)?;
518 context.timing.stop();
519
520 if context.debug_enabled {
521 context
522 .timing
523 .start("debug_print:RewriteInstructionKindsBasedOnReassignment");
524 let debug_rewrite = debug_print::debug_hir(&hir, &env);
525 context.log_debug(DebugLogEntry::new(
526 "RewriteInstructionKindsBasedOnReassignment",
527 debug_rewrite,
528 ));
529 context.timing.stop();
530 }
531
532 if env.enable_validations()
533 && env.config.validate_static_components
534 && env.output_mode == OutputMode::Lint
535 {
536 context.timing.start("ValidateStaticComponents");
537 let errors = react_compiler_validation::validate_static_components(&hir);
538 log_errors_as_events(&errors, context);
539 if context.debug_enabled {
540 context.log_debug(DebugLogEntry::new(
541 "ValidateStaticComponents",
542 "ok".to_string(),
543 ));
544 }
545 context.timing.stop();
546 }
547
548 if env.enable_memoization() {
549 context.timing.start("InferReactiveScopeVariables");
550 react_compiler_inference::infer_reactive_scope_variables(&mut hir, &mut env)?;
551 context.timing.stop();
552
553 if context.debug_enabled {
554 context
555 .timing
556 .start("debug_print:InferReactiveScopeVariables");
557 let debug_infer_scopes = debug_print::debug_hir(&hir, &env);
558 context.log_debug(DebugLogEntry::new(
559 "InferReactiveScopeVariables",
560 debug_infer_scopes,
561 ));
562 context.timing.stop();
563 }
564 }
565
566 context
567 .timing
568 .start("MemoizeFbtAndMacroOperandsInSameScope");
569 let fbt_operands =
570 react_compiler_inference::memoize_fbt_and_macro_operands_in_same_scope(&hir, &mut env);
571 context.timing.stop();
572
573 if context.debug_enabled {
574 context
575 .timing
576 .start("debug_print:MemoizeFbtAndMacroOperandsInSameScope");
577 let debug_fbt = debug_print::debug_hir(&hir, &env);
578 context.log_debug(DebugLogEntry::new(
579 "MemoizeFbtAndMacroOperandsInSameScope",
580 debug_fbt,
581 ));
582 context.timing.stop();
583 }
584
585 if env.config.enable_jsx_outlining {
586 context.timing.start("OutlineJsx");
587 react_compiler_optimization::outline_jsx(&mut hir, &mut env);
588 context.timing.stop();
589 }
590
591 if env.config.enable_name_anonymous_functions {
592 context.timing.start("NameAnonymousFunctions");
593 react_compiler_optimization::name_anonymous_functions(&mut hir, &mut env);
594 context.timing.stop();
595
596 if context.debug_enabled {
597 context.timing.start("debug_print:NameAnonymousFunctions");
598 let debug_name_anon = debug_print::debug_hir(&hir, &env);
599 context.log_debug(DebugLogEntry::new(
600 "NameAnonymousFunctions",
601 debug_name_anon,
602 ));
603 context.timing.stop();
604 }
605 }
606
607 if env.config.enable_function_outlining {
608 context.timing.start("OutlineFunctions");
609 react_compiler_optimization::outline_functions(&mut hir, &mut env, &fbt_operands);
610 context.timing.stop();
611
612 if context.debug_enabled {
613 context.timing.start("debug_print:OutlineFunctions");
614 let debug_outline = debug_print::debug_hir(&hir, &env);
615 context.log_debug(DebugLogEntry::new("OutlineFunctions", debug_outline));
616 context.timing.stop();
617 }
618 }
619
620 context.timing.start("AlignMethodCallScopes");
621 react_compiler_inference::align_method_call_scopes(&mut hir, &mut env);
622 context.timing.stop();
623
624 if context.debug_enabled {
625 context.timing.start("debug_print:AlignMethodCallScopes");
626 let debug_align = debug_print::debug_hir(&hir, &env);
627 context.log_debug(DebugLogEntry::new("AlignMethodCallScopes", debug_align));
628 context.timing.stop();
629 }
630
631 context.timing.start("AlignObjectMethodScopes");
632 react_compiler_inference::align_object_method_scopes(&mut hir, &mut env);
633 context.timing.stop();
634
635 if context.debug_enabled {
636 context.timing.start("debug_print:AlignObjectMethodScopes");
637 let debug_align_obj = debug_print::debug_hir(&hir, &env);
638 context.log_debug(DebugLogEntry::new(
639 "AlignObjectMethodScopes",
640 debug_align_obj,
641 ));
642 context.timing.stop();
643 }
644
645 context.timing.start("PruneUnusedLabelsHIR");
646 react_compiler_optimization::prune_unused_labels_hir(&mut hir);
647 context.timing.stop();
648
649 if context.debug_enabled {
650 context.timing.start("debug_print:PruneUnusedLabelsHIR");
651 let debug_prune_labels = debug_print::debug_hir(&hir, &env);
652 context.log_debug(DebugLogEntry::new(
653 "PruneUnusedLabelsHIR",
654 debug_prune_labels,
655 ));
656 context.timing.stop();
657 }
658
659 context.timing.start("AlignReactiveScopesToBlockScopesHIR");
660 react_compiler_inference::align_reactive_scopes_to_block_scopes_hir(&mut hir, &mut env);
661 context.timing.stop();
662
663 if context.debug_enabled {
664 context
665 .timing
666 .start("debug_print:AlignReactiveScopesToBlockScopesHIR");
667 let debug_align_block_scopes = debug_print::debug_hir(&hir, &env);
668 context.log_debug(DebugLogEntry::new(
669 "AlignReactiveScopesToBlockScopesHIR",
670 debug_align_block_scopes,
671 ));
672 context.timing.stop();
673 }
674
675 context.timing.start("MergeOverlappingReactiveScopesHIR");
676 react_compiler_inference::merge_overlapping_reactive_scopes_hir(&mut hir, &mut env);
677 context.timing.stop();
678
679 if context.debug_enabled {
680 context
681 .timing
682 .start("debug_print:MergeOverlappingReactiveScopesHIR");
683 let debug_merge_overlapping = debug_print::debug_hir(&hir, &env);
684 context.log_debug(DebugLogEntry::new(
685 "MergeOverlappingReactiveScopesHIR",
686 debug_merge_overlapping,
687 ));
688 context.timing.stop();
689 }
690
691 if context.debug_enabled {
693 context.log_debug(DebugLogEntry::new(
694 "AssertValidBlockNesting",
695 "ok".to_string(),
696 ));
697 }
698
699 context.timing.start("BuildReactiveScopeTerminalsHIR");
700 react_compiler_inference::build_reactive_scope_terminals_hir(&mut hir, &mut env);
701 context.timing.stop();
702
703 if context.debug_enabled {
704 context
705 .timing
706 .start("debug_print:BuildReactiveScopeTerminalsHIR");
707 let debug_build_scope_terminals = debug_print::debug_hir(&hir, &env);
708 context.log_debug(DebugLogEntry::new(
709 "BuildReactiveScopeTerminalsHIR",
710 debug_build_scope_terminals,
711 ));
712 context.timing.stop();
713 }
714
715 if context.debug_enabled {
717 context.log_debug(DebugLogEntry::new(
718 "AssertValidBlockNesting",
719 "ok".to_string(),
720 ));
721 }
722
723 context.timing.start("FlattenReactiveLoopsHIR");
724 react_compiler_inference::flatten_reactive_loops_hir(&mut hir);
725 context.timing.stop();
726
727 if context.debug_enabled {
728 context.timing.start("debug_print:FlattenReactiveLoopsHIR");
729 let debug_flatten_loops = debug_print::debug_hir(&hir, &env);
730 context.log_debug(DebugLogEntry::new(
731 "FlattenReactiveLoopsHIR",
732 debug_flatten_loops,
733 ));
734 context.timing.stop();
735 }
736
737 context.timing.start("FlattenScopesWithHooksOrUseHIR");
738 react_compiler_inference::flatten_scopes_with_hooks_or_use_hir(&mut hir, &env)?;
739 context.timing.stop();
740
741 if context.debug_enabled {
742 context
743 .timing
744 .start("debug_print:FlattenScopesWithHooksOrUseHIR");
745 let debug_flatten_hooks = debug_print::debug_hir(&hir, &env);
746 context.log_debug(DebugLogEntry::new(
747 "FlattenScopesWithHooksOrUseHIR",
748 debug_flatten_hooks,
749 ));
750 context.timing.stop();
751 }
752
753 if context.debug_enabled {
755 context.log_debug(DebugLogEntry::new(
756 "AssertTerminalSuccessorsExist",
757 "ok".to_string(),
758 ));
759 }
760 if context.debug_enabled {
762 context.log_debug(DebugLogEntry::new(
763 "AssertTerminalPredsExist",
764 "ok".to_string(),
765 ));
766 }
767
768 context.timing.start("PropagateScopeDependenciesHIR");
769 react_compiler_inference::propagate_scope_dependencies_hir(&mut hir, &mut env);
770 context.timing.stop();
771
772 if context.debug_enabled {
773 context
774 .timing
775 .start("debug_print:PropagateScopeDependenciesHIR");
776 let debug_propagate_deps = debug_print::debug_hir(&hir, &env);
777 context.log_debug(DebugLogEntry::new(
778 "PropagateScopeDependenciesHIR",
779 debug_propagate_deps,
780 ));
781 context.timing.stop();
782 }
783
784 context.timing.start("BuildReactiveFunction");
785 let mut reactive_fn = react_compiler_reactive_scopes::build_reactive_function(&hir, &env)?;
786 context.timing.stop();
787
788 let hir_formatter = |fmt: &mut react_compiler_hir::print::PrintFormatter,
789 func: &react_compiler_hir::HirFunction| {
790 debug_print::format_hir_function_into(fmt, func);
791 };
792
793 if context.debug_enabled {
794 context.timing.start("debug_print:BuildReactiveFunction");
795 let debug_reactive = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(
796 &reactive_fn, &env, Some(&hir_formatter),
797 );
798 context.log_debug(DebugLogEntry::new("BuildReactiveFunction", debug_reactive));
799 context.timing.stop();
800 }
801
802 context.timing.start("AssertWellFormedBreakTargets");
803 react_compiler_reactive_scopes::assert_well_formed_break_targets(&reactive_fn, &env);
804 if context.debug_enabled {
805 context.log_debug(DebugLogEntry::new(
806 "AssertWellFormedBreakTargets",
807 "ok".to_string(),
808 ));
809 }
810 context.timing.stop();
811
812 context.timing.start("PruneUnusedLabels");
813 react_compiler_reactive_scopes::prune_unused_labels(&mut reactive_fn, &env)?;
814 context.timing.stop();
815
816 if context.debug_enabled {
817 context.timing.start("debug_print:PruneUnusedLabels");
818 let debug_prune_labels_reactive = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(
819 &reactive_fn, &env, Some(&hir_formatter),
820 );
821 context.log_debug(DebugLogEntry::new(
822 "PruneUnusedLabels",
823 debug_prune_labels_reactive,
824 ));
825 context.timing.stop();
826 }
827
828 context.timing.start("AssertScopeInstructionsWithinScopes");
829 react_compiler_reactive_scopes::assert_scope_instructions_within_scopes(&reactive_fn, &env)?;
830 if context.debug_enabled {
831 context.log_debug(DebugLogEntry::new(
832 "AssertScopeInstructionsWithinScopes",
833 "ok".to_string(),
834 ));
835 }
836 context.timing.stop();
837
838 context.timing.start("PruneNonEscapingScopes");
839 react_compiler_reactive_scopes::prune_non_escaping_scopes(&mut reactive_fn, &mut env)?;
840 context.timing.stop();
841
842 if context.debug_enabled {
843 context.timing.start("debug_print:PruneNonEscapingScopes");
844 let debug = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(
845 &reactive_fn, &env, Some(&hir_formatter),
846 );
847 context.log_debug(DebugLogEntry::new("PruneNonEscapingScopes", debug));
848 context.timing.stop();
849 }
850
851 context.timing.start("PruneNonReactiveDependencies");
852 react_compiler_reactive_scopes::prune_non_reactive_dependencies(&mut reactive_fn, &mut env);
853 context.timing.stop();
854
855 if context.debug_enabled {
856 context
857 .timing
858 .start("debug_print:PruneNonReactiveDependencies");
859 let debug_prune_non_reactive = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(
860 &reactive_fn, &env, Some(&hir_formatter),
861 );
862 context.log_debug(DebugLogEntry::new(
863 "PruneNonReactiveDependencies",
864 debug_prune_non_reactive,
865 ));
866 context.timing.stop();
867 }
868
869 context.timing.start("PruneUnusedScopes");
870 react_compiler_reactive_scopes::prune_unused_scopes(&mut reactive_fn, &env)?;
871 context.timing.stop();
872
873 if context.debug_enabled {
874 context.timing.start("debug_print:PruneUnusedScopes");
875 let debug_prune_unused_scopes = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(
876 &reactive_fn, &env, Some(&hir_formatter),
877 );
878 context.log_debug(DebugLogEntry::new(
879 "PruneUnusedScopes",
880 debug_prune_unused_scopes,
881 ));
882 context.timing.stop();
883 }
884
885 context
886 .timing
887 .start("MergeReactiveScopesThatInvalidateTogether");
888 react_compiler_reactive_scopes::merge_reactive_scopes_that_invalidate_together(
889 &mut reactive_fn,
890 &mut env,
891 )?;
892 context.timing.stop();
893
894 if context.debug_enabled {
895 context
896 .timing
897 .start("debug_print:MergeReactiveScopesThatInvalidateTogether");
898 let debug = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(
899 &reactive_fn, &env, Some(&hir_formatter),
900 );
901 context.log_debug(DebugLogEntry::new(
902 "MergeReactiveScopesThatInvalidateTogether",
903 debug,
904 ));
905 context.timing.stop();
906 }
907
908 context.timing.start("PruneAlwaysInvalidatingScopes");
909 react_compiler_reactive_scopes::prune_always_invalidating_scopes(&mut reactive_fn, &env)?;
910 context.timing.stop();
911
912 if context.debug_enabled {
913 context
914 .timing
915 .start("debug_print:PruneAlwaysInvalidatingScopes");
916 let debug_prune_always_inv = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(
917 &reactive_fn, &env, Some(&hir_formatter),
918 );
919 context.log_debug(DebugLogEntry::new(
920 "PruneAlwaysInvalidatingScopes",
921 debug_prune_always_inv,
922 ));
923 context.timing.stop();
924 }
925
926 context.timing.start("PropagateEarlyReturns");
927 react_compiler_reactive_scopes::propagate_early_returns(&mut reactive_fn, &mut env);
928 context.timing.stop();
929
930 if context.debug_enabled {
931 context.timing.start("debug_print:PropagateEarlyReturns");
932 let debug = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(
933 &reactive_fn, &env, Some(&hir_formatter),
934 );
935 context.log_debug(DebugLogEntry::new("PropagateEarlyReturns", debug));
936 context.timing.stop();
937 }
938
939 context.timing.start("PruneUnusedLValues");
940 react_compiler_reactive_scopes::prune_unused_lvalues(&mut reactive_fn, &env);
941 context.timing.stop();
942
943 if context.debug_enabled {
944 context.timing.start("debug_print:PruneUnusedLValues");
945 let debug_prune_lvalues = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(
946 &reactive_fn, &env, Some(&hir_formatter),
947 );
948 context.log_debug(DebugLogEntry::new(
949 "PruneUnusedLValues",
950 debug_prune_lvalues,
951 ));
952 context.timing.stop();
953 }
954
955 context.timing.start("PromoteUsedTemporaries");
956 react_compiler_reactive_scopes::promote_used_temporaries(&mut reactive_fn, &mut env);
957 context.timing.stop();
958
959 if context.debug_enabled {
960 context.timing.start("debug_print:PromoteUsedTemporaries");
961 let debug = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(
962 &reactive_fn, &env, Some(&hir_formatter),
963 );
964 context.log_debug(DebugLogEntry::new("PromoteUsedTemporaries", debug));
965 context.timing.stop();
966 }
967
968 context
969 .timing
970 .start("ExtractScopeDeclarationsFromDestructuring");
971 react_compiler_reactive_scopes::extract_scope_declarations_from_destructuring(
972 &mut reactive_fn,
973 &mut env,
974 )?;
975 context.timing.stop();
976
977 if context.debug_enabled {
978 context
979 .timing
980 .start("debug_print:ExtractScopeDeclarationsFromDestructuring");
981 let debug = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(
982 &reactive_fn, &env, Some(&hir_formatter),
983 );
984 context.log_debug(DebugLogEntry::new(
985 "ExtractScopeDeclarationsFromDestructuring",
986 debug,
987 ));
988 context.timing.stop();
989 }
990
991 context.timing.start("StabilizeBlockIds");
992 react_compiler_reactive_scopes::stabilize_block_ids(&mut reactive_fn, &mut env);
993 context.timing.stop();
994
995 if context.debug_enabled {
996 context.timing.start("debug_print:StabilizeBlockIds");
997 let debug_stabilize = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(
998 &reactive_fn, &env, Some(&hir_formatter),
999 );
1000 context.log_debug(DebugLogEntry::new("StabilizeBlockIds", debug_stabilize));
1001 context.timing.stop();
1002 }
1003
1004 context.timing.start("RenameVariables");
1005 let unique_identifiers =
1006 react_compiler_reactive_scopes::rename_variables(&mut reactive_fn, &mut env);
1007 context.timing.stop();
1008
1009 for name in &unique_identifiers {
1010 context.add_new_reference(name.clone());
1011 }
1012
1013 if context.debug_enabled {
1014 context.timing.start("debug_print:RenameVariables");
1015 let debug = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(
1016 &reactive_fn, &env, Some(&hir_formatter),
1017 );
1018 context.log_debug(DebugLogEntry::new("RenameVariables", debug));
1019 context.timing.stop();
1020 }
1021
1022 context.timing.start("PruneHoistedContexts");
1023 react_compiler_reactive_scopes::prune_hoisted_contexts(&mut reactive_fn, &mut env)?;
1024 context.timing.stop();
1025
1026 if context.debug_enabled {
1027 context.timing.start("debug_print:PruneHoistedContexts");
1028 let debug = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(
1029 &reactive_fn, &env, Some(&hir_formatter),
1030 );
1031 context.log_debug(DebugLogEntry::new("PruneHoistedContexts", debug));
1032 context.timing.stop();
1033 }
1034
1035 if env.config.enable_preserve_existing_memoization_guarantees
1036 || env.config.validate_preserve_existing_memoization_guarantees
1037 {
1038 context.timing.start("ValidatePreservedManualMemoization");
1039 react_compiler_validation::validate_preserved_manual_memoization(&reactive_fn, &mut env);
1040 if context.debug_enabled {
1041 context.log_debug(DebugLogEntry::new(
1042 "ValidatePreservedManualMemoization",
1043 "ok".to_string(),
1044 ));
1045 }
1046 context.timing.stop();
1047 }
1048
1049 context.timing.start("codegen");
1050 let codegen_result = react_compiler_reactive_scopes::codegen_function(
1051 &reactive_fn,
1052 &mut env,
1053 unique_identifiers,
1054 fbt_operands,
1055 )?;
1056 context.timing.stop();
1057
1058 if env.config.validate_source_locations {
1066 super::validate_source_locations::validate_source_locations(
1067 func,
1068 &codegen_result,
1069 &mut env,
1070 );
1071 }
1072
1073 if env.config.throw_unknown_exception_testonly {
1075 let mut err = CompilerError::new();
1076 err.push_error_detail(react_compiler_diagnostics::CompilerErrorDetail {
1077 category: react_compiler_diagnostics::ErrorCategory::Invariant,
1078 reason: "unexpected error".to_string(),
1079 description: None,
1080 loc: None,
1081 suggestions: None,
1082 });
1083 return Err(err);
1084 }
1085
1086 if env.has_errors() {
1089 if let Some(uid_names) = env.take_uid_known_names() {
1095 context.merge_uid_known_names(&uid_names);
1096 }
1097 return Err(env.take_errors());
1098 }
1099
1100 let mut compiled_outlined: Vec<OutlinedFunction> = Vec::new();
1104 for o in codegen_result.outlined {
1105 let outlined_codegen = CodegenFunction {
1106 loc: o.func.loc,
1107 id: o.func.id,
1108 name_hint: o.func.name_hint,
1109 params: o.func.params,
1110 body: o.func.body,
1111 generator: o.func.generator,
1112 is_async: o.func.is_async,
1113 memo_slots_used: o.func.memo_slots_used,
1114 memo_blocks: o.func.memo_blocks,
1115 memo_values: o.func.memo_values,
1116 pruned_memo_blocks: o.func.pruned_memo_blocks,
1117 pruned_memo_values: o.func.pruned_memo_values,
1118 outlined: Vec::new(),
1119 };
1120 if let Some(fn_type) = o.fn_type {
1121 let fn_name = outlined_codegen.id.as_ref().map(|id| id.name.clone());
1122 match compile_outlined_fn(
1123 outlined_codegen,
1124 fn_name.as_deref(),
1125 fn_type,
1126 mode,
1127 env_config,
1128 context,
1129 ) {
1130 Ok(compiled) => {
1131 compiled_outlined.push(OutlinedFunction {
1132 func: compiled,
1133 fn_type: Some(fn_type),
1134 });
1135 }
1136 Err(_err) => {
1137 }
1139 }
1140 } else {
1141 compiled_outlined.push(OutlinedFunction {
1142 func: outlined_codegen,
1143 fn_type: o.fn_type,
1144 });
1145 }
1146 }
1147
1148 if let Some(uid_names) = env.take_uid_known_names() {
1149 context.merge_uid_known_names(&uid_names);
1150 }
1151
1152 Ok(CodegenFunction {
1153 loc: codegen_result.loc,
1154 id: codegen_result.id,
1155 name_hint: codegen_result.name_hint,
1156 params: codegen_result.params,
1157 body: codegen_result.body,
1158 generator: codegen_result.generator,
1159 is_async: codegen_result.is_async,
1160 memo_slots_used: codegen_result.memo_slots_used,
1161 memo_blocks: codegen_result.memo_blocks,
1162 memo_values: codegen_result.memo_values,
1163 pruned_memo_blocks: codegen_result.pruned_memo_blocks,
1164 pruned_memo_values: codegen_result.pruned_memo_values,
1165 outlined: compiled_outlined,
1166 })
1167}
1168
1169pub fn compile_outlined_fn(
1176 mut codegen_fn: CodegenFunction,
1177 fn_name: Option<&str>,
1178 fn_type: ReactFunctionType,
1179 mode: CompilerOutputMode,
1180 env_config: &EnvironmentConfig,
1181 context: &mut ProgramContext,
1182) -> Result<CodegenFunction, CompilerError> {
1183 let mut env = Environment::with_config(env_config.clone());
1184 env.fn_type = fn_type;
1185 env.output_mode = match mode {
1186 CompilerOutputMode::Ssr => OutputMode::Ssr,
1187 CompilerOutputMode::Client => OutputMode::Client,
1188 CompilerOutputMode::Lint => OutputMode::Lint,
1189 };
1190
1191 let mut outlined_decl = react_compiler_ast::statements::FunctionDeclaration {
1193 base: react_compiler_ast::common::BaseNode::typed("FunctionDeclaration"),
1194 id: codegen_fn.id.take(),
1195 params: std::mem::take(&mut codegen_fn.params),
1196 body: std::mem::replace(
1197 &mut codegen_fn.body,
1198 react_compiler_ast::statements::BlockStatement {
1199 base: react_compiler_ast::common::BaseNode::typed("BlockStatement"),
1200 body: Vec::new(),
1201 directives: Vec::new(),
1202 },
1203 ),
1204 generator: codegen_fn.generator,
1205 is_async: codegen_fn.is_async,
1206 declare: None,
1207 return_type: None,
1208 type_parameters: None,
1209 predicate: None,
1210 component_declaration: false,
1211 hook_declaration: false,
1212 };
1213
1214 let scope_info = build_outlined_scope_info(&mut outlined_decl);
1216
1217 let func_node = react_compiler_lowering::FunctionNode::FunctionDeclaration(&outlined_decl);
1218 let mut hir = react_compiler_lowering::lower(&func_node, fn_name, &scope_info, &mut env)?;
1219
1220 if env.has_invariant_errors() {
1221 return Err(env.take_invariant_errors());
1222 }
1223
1224 run_pipeline_passes(&mut hir, &mut env, context)
1225}
1226
1227fn build_outlined_scope_info(
1230 func: &mut react_compiler_ast::statements::FunctionDeclaration,
1231) -> react_compiler_ast::scope::ScopeInfo {
1232 use std::collections::HashMap;
1233
1234 use react_compiler_ast::scope::*;
1235
1236 let mut pos: u32 = 1; func.base.start = Some(0);
1238
1239 let mut fn_bindings: HashMap<String, BindingId> = HashMap::new();
1240 let mut bindings_list: Vec<BindingData> = Vec::new();
1241 let mut ref_to_binding: indexmap::IndexMap<u32, BindingId> = indexmap::IndexMap::new();
1242
1243 let _add_binding =
1245 |name: &str,
1246 kind: BindingKind,
1247 p: u32,
1248 fn_bindings: &mut HashMap<String, BindingId>,
1249 bindings_list: &mut Vec<BindingData>,
1250 ref_to_binding: &mut indexmap::IndexMap<u32, BindingId>| {
1251 if fn_bindings.contains_key(name) {
1252 let bid = fn_bindings[name];
1254 ref_to_binding.insert(p, bid);
1255 return;
1256 }
1257 let binding_id = BindingId(bindings_list.len() as u32);
1258 fn_bindings.insert(name.to_string(), binding_id);
1259 bindings_list.push(BindingData {
1260 id: binding_id,
1261 name: name.to_string(),
1262 kind,
1263 scope: ScopeId(1),
1264 declaration_type: "VariableDeclarator".to_string(),
1265 declaration_start: Some(p),
1266 declaration_node_id: None,
1267 import: None,
1268 });
1269 ref_to_binding.insert(p, binding_id);
1270 };
1271
1272 for param in &mut func.params {
1274 outlined_assign_pattern_positions(
1275 param,
1276 &mut pos,
1277 BindingKind::Param,
1278 &mut fn_bindings,
1279 &mut bindings_list,
1280 &mut ref_to_binding,
1281 );
1282 }
1283
1284 for stmt in &mut func.body.body {
1286 outlined_assign_stmt_positions(
1287 stmt,
1288 &mut pos,
1289 &mut fn_bindings,
1290 &mut bindings_list,
1291 &mut ref_to_binding,
1292 );
1293 }
1294
1295 let program_scope = ScopeData {
1296 id: ScopeId(0),
1297 parent: None,
1298 kind: ScopeKind::Program,
1299 bindings: HashMap::new(),
1300 };
1301 let fn_scope = ScopeData {
1302 id: ScopeId(1),
1303 parent: Some(ScopeId(0)),
1304 kind: ScopeKind::Function,
1305 bindings: fn_bindings,
1306 };
1307
1308 let mut node_to_scope: HashMap<u32, ScopeId> = HashMap::new();
1309 node_to_scope.insert(0, ScopeId(1));
1310
1311 let mut node_id_to_scope: HashMap<u32, ScopeId> = HashMap::new();
1313 node_id_to_scope.insert(0, ScopeId(1));
1314 let ref_node_id_to_binding: indexmap::IndexMap<u32, BindingId> =
1315 ref_to_binding.iter().map(|(&k, &v)| (k, v)).collect();
1316
1317 ScopeInfo {
1318 scopes: vec![program_scope, fn_scope],
1319 bindings: bindings_list,
1320 node_to_scope,
1321 node_to_scope_end: HashMap::new(),
1322 reference_to_binding: indexmap::IndexMap::new(),
1323 ref_node_id_to_binding,
1324 node_id_to_scope,
1325 program_scope: ScopeId(0),
1326 }
1327}
1328
1329fn outlined_assign_pattern_positions(
1331 pattern: &mut react_compiler_ast::patterns::PatternLike,
1332 pos: &mut u32,
1333 kind: react_compiler_ast::scope::BindingKind,
1334 fn_bindings: &mut std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
1335 bindings_list: &mut Vec<react_compiler_ast::scope::BindingData>,
1336 ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
1337) {
1338 use react_compiler_ast::patterns::PatternLike;
1339 use react_compiler_ast::scope::*;
1340
1341 match pattern {
1342 PatternLike::Identifier(id) => {
1343 let p = *pos;
1344 *pos += 1;
1345 id.base.start = Some(p);
1346 id.base.node_id = Some(p);
1347 if !fn_bindings.contains_key(&id.name) {
1349 let binding_id = BindingId(bindings_list.len() as u32);
1350 fn_bindings.insert(id.name.clone(), binding_id);
1351 bindings_list.push(BindingData {
1352 id: binding_id,
1353 name: id.name.clone(),
1354 kind: kind.clone(),
1355 scope: ScopeId(1),
1356 declaration_type: "VariableDeclarator".to_string(),
1357 declaration_start: Some(p),
1358 declaration_node_id: Some(p),
1359 import: None,
1360 });
1361 ref_to_binding.insert(p, binding_id);
1362 } else {
1363 let bid = fn_bindings[&id.name];
1364 ref_to_binding.insert(p, bid);
1365 }
1366 }
1367 PatternLike::ObjectPattern(obj) => {
1368 for prop in &mut obj.properties {
1369 match prop {
1370 react_compiler_ast::patterns::ObjectPatternProperty::ObjectProperty(
1371 p_inner,
1372 ) => {
1373 outlined_assign_pattern_positions(
1374 &mut p_inner.value,
1375 pos,
1376 kind.clone(),
1377 fn_bindings,
1378 bindings_list,
1379 ref_to_binding,
1380 );
1381 }
1382 react_compiler_ast::patterns::ObjectPatternProperty::RestElement(r) => {
1383 outlined_assign_pattern_positions(
1384 &mut r.argument,
1385 pos,
1386 kind.clone(),
1387 fn_bindings,
1388 bindings_list,
1389 ref_to_binding,
1390 );
1391 }
1392 }
1393 }
1394 }
1395 PatternLike::ArrayPattern(arr) => {
1396 for elem in arr.elements.iter_mut().flatten() {
1397 outlined_assign_pattern_positions(
1398 elem,
1399 pos,
1400 kind.clone(),
1401 fn_bindings,
1402 bindings_list,
1403 ref_to_binding,
1404 );
1405 }
1406 }
1407 PatternLike::AssignmentPattern(assign) => {
1408 outlined_assign_pattern_positions(
1409 &mut assign.left,
1410 pos,
1411 kind.clone(),
1412 fn_bindings,
1413 bindings_list,
1414 ref_to_binding,
1415 );
1416 }
1417 PatternLike::RestElement(rest) => {
1418 outlined_assign_pattern_positions(
1419 &mut rest.argument,
1420 pos,
1421 kind.clone(),
1422 fn_bindings,
1423 bindings_list,
1424 ref_to_binding,
1425 );
1426 }
1427 _ => {}
1428 }
1429}
1430
1431fn outlined_assign_stmt_positions(
1433 stmt: &mut react_compiler_ast::statements::Statement,
1434 pos: &mut u32,
1435 fn_bindings: &mut std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
1436 bindings_list: &mut Vec<react_compiler_ast::scope::BindingData>,
1437 ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
1438) {
1439 use react_compiler_ast::statements::Statement;
1440
1441 match stmt {
1442 Statement::VariableDeclaration(decl) => {
1443 for declarator in &mut decl.declarations {
1444 if let Some(init) = &mut declarator.init {
1446 outlined_assign_expr_positions(init, pos, fn_bindings, ref_to_binding);
1447 }
1448 outlined_assign_pattern_positions(
1450 &mut declarator.id,
1451 pos,
1452 react_compiler_ast::scope::BindingKind::Let,
1453 fn_bindings,
1454 bindings_list,
1455 ref_to_binding,
1456 );
1457 }
1458 }
1459 Statement::ReturnStatement(ret) => {
1460 if let Some(arg) = &mut ret.argument {
1461 outlined_assign_expr_positions(arg, pos, fn_bindings, ref_to_binding);
1462 }
1463 }
1464 Statement::ExpressionStatement(expr_stmt) => {
1465 outlined_assign_expr_positions(
1466 &mut expr_stmt.expression,
1467 pos,
1468 fn_bindings,
1469 ref_to_binding,
1470 );
1471 }
1472 _ => {}
1473 }
1474}
1475
1476fn outlined_assign_expr_positions(
1478 expr: &mut react_compiler_ast::expressions::Expression,
1479 pos: &mut u32,
1480 fn_bindings: &std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
1481 ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
1482) {
1483 use react_compiler_ast::expressions::*;
1484
1485 match expr {
1486 Expression::Identifier(id) => {
1487 let p = *pos;
1488 *pos += 1;
1489 id.base.start = Some(p);
1490 id.base.node_id = Some(p);
1491 if let Some(&bid) = fn_bindings.get(&id.name) {
1492 ref_to_binding.insert(p, bid);
1493 }
1494 }
1495 Expression::JSXElement(jsx) => {
1496 outlined_assign_jsx_name_positions(
1498 &mut jsx.opening_element.name,
1499 pos,
1500 fn_bindings,
1501 ref_to_binding,
1502 );
1503 for attr in &mut jsx.opening_element.attributes {
1504 match attr {
1505 react_compiler_ast::jsx::JSXAttributeItem::JSXAttribute(a) => {
1506 if let Some(val) = &mut a.value {
1507 outlined_assign_jsx_val_positions(
1508 val,
1509 pos,
1510 fn_bindings,
1511 ref_to_binding,
1512 );
1513 }
1514 }
1515 react_compiler_ast::jsx::JSXAttributeItem::JSXSpreadAttribute(s) => {
1516 outlined_assign_expr_positions(
1517 &mut s.argument,
1518 pos,
1519 fn_bindings,
1520 ref_to_binding,
1521 );
1522 }
1523 }
1524 }
1525 for child in &mut jsx.children {
1526 outlined_assign_jsx_child_positions(child, pos, fn_bindings, ref_to_binding);
1527 }
1528 }
1529 Expression::JSXFragment(frag) => {
1530 for child in &mut frag.children {
1531 outlined_assign_jsx_child_positions(child, pos, fn_bindings, ref_to_binding);
1532 }
1533 }
1534 _ => {}
1535 }
1536}
1537
1538fn outlined_assign_jsx_name_positions(
1539 name: &mut react_compiler_ast::jsx::JSXElementName,
1540 pos: &mut u32,
1541 fn_bindings: &std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
1542 ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
1543) {
1544 match name {
1545 react_compiler_ast::jsx::JSXElementName::JSXIdentifier(id) => {
1546 let p = *pos;
1547 *pos += 1;
1548 id.base.start = Some(p);
1549 id.base.node_id = Some(p);
1550 if let Some(&bid) = fn_bindings.get(&id.name) {
1551 ref_to_binding.insert(p, bid);
1552 }
1553 }
1554 react_compiler_ast::jsx::JSXElementName::JSXMemberExpression(m) => {
1555 outlined_assign_jsx_member_positions(m, pos, fn_bindings, ref_to_binding);
1556 }
1557 _ => {}
1558 }
1559}
1560
1561fn outlined_assign_jsx_member_positions(
1562 member: &mut react_compiler_ast::jsx::JSXMemberExpression,
1563 pos: &mut u32,
1564 fn_bindings: &std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
1565 ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
1566) {
1567 match &mut *member.object {
1568 react_compiler_ast::jsx::JSXMemberExprObject::JSXIdentifier(id) => {
1569 let p = *pos;
1570 *pos += 1;
1571 id.base.start = Some(p);
1572 id.base.node_id = Some(p);
1573 if let Some(&bid) = fn_bindings.get(&id.name) {
1574 ref_to_binding.insert(p, bid);
1575 }
1576 }
1577 react_compiler_ast::jsx::JSXMemberExprObject::JSXMemberExpression(inner) => {
1578 outlined_assign_jsx_member_positions(inner, pos, fn_bindings, ref_to_binding);
1579 }
1580 }
1581}
1582
1583fn outlined_assign_jsx_val_positions(
1584 val: &mut react_compiler_ast::jsx::JSXAttributeValue,
1585 pos: &mut u32,
1586 fn_bindings: &std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
1587 ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
1588) {
1589 match val {
1590 react_compiler_ast::jsx::JSXAttributeValue::JSXExpressionContainer(c) => {
1591 if let react_compiler_ast::jsx::JSXExpressionContainerExpr::Expression(e) =
1592 &mut c.expression
1593 {
1594 outlined_assign_expr_positions(e, pos, fn_bindings, ref_to_binding);
1595 }
1596 }
1597 react_compiler_ast::jsx::JSXAttributeValue::JSXElement(el) => {
1598 let mut expr = react_compiler_ast::expressions::Expression::JSXElement(el.clone());
1599 outlined_assign_expr_positions(&mut expr, pos, fn_bindings, ref_to_binding);
1600 if let react_compiler_ast::expressions::Expression::JSXElement(new_el) = expr {
1601 **el = *new_el;
1602 }
1603 }
1604 _ => {}
1605 }
1606}
1607
1608fn outlined_assign_jsx_child_positions(
1609 child: &mut react_compiler_ast::jsx::JSXChild,
1610 pos: &mut u32,
1611 fn_bindings: &std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
1612 ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
1613) {
1614 match child {
1615 react_compiler_ast::jsx::JSXChild::JSXExpressionContainer(c) => {
1616 if let react_compiler_ast::jsx::JSXExpressionContainerExpr::Expression(e) =
1617 &mut c.expression
1618 {
1619 outlined_assign_expr_positions(e, pos, fn_bindings, ref_to_binding);
1620 }
1621 }
1622 react_compiler_ast::jsx::JSXChild::JSXElement(el) => {
1623 let mut expr =
1624 react_compiler_ast::expressions::Expression::JSXElement(Box::new(*el.clone()));
1625 outlined_assign_expr_positions(&mut expr, pos, fn_bindings, ref_to_binding);
1626 if let react_compiler_ast::expressions::Expression::JSXElement(new_el) = expr {
1627 **el = *new_el;
1628 }
1629 }
1630 react_compiler_ast::jsx::JSXChild::JSXFragment(frag) => {
1631 for inner in &mut frag.children {
1632 outlined_assign_jsx_child_positions(inner, pos, fn_bindings, ref_to_binding);
1633 }
1634 }
1635 _ => {}
1636 }
1637}
1638fn run_pipeline_passes(
1645 hir: &mut react_compiler_hir::HirFunction,
1646 env: &mut Environment,
1647 context: &mut ProgramContext,
1648) -> Result<CodegenFunction, CompilerError> {
1649 react_compiler_optimization::prune_maybe_throws(hir, &mut env.functions)?;
1650
1651 react_compiler_optimization::drop_manual_memoization(hir, env)?;
1652
1653 react_compiler_optimization::inline_immediately_invoked_function_expressions(hir, env);
1654
1655 react_compiler_optimization::merge_consecutive_blocks::merge_consecutive_blocks(
1656 hir,
1657 &mut env.functions,
1658 );
1659
1660 react_compiler_ssa::enter_ssa(hir, env).map_err(|diag| {
1661 let loc = diag.primary_location().cloned();
1662 let mut err = CompilerError::new();
1663 err.push_error_detail(react_compiler_diagnostics::CompilerErrorDetail {
1664 category: diag.category,
1665 reason: diag.reason,
1666 description: diag.description,
1667 loc,
1668 suggestions: diag.suggestions,
1669 });
1670 err
1671 })?;
1672
1673 react_compiler_ssa::eliminate_redundant_phi(hir, env);
1674
1675 react_compiler_optimization::constant_propagation(hir, env);
1676
1677 react_compiler_typeinference::infer_types(hir, env)?;
1678
1679 if env.enable_validations() {
1680 if env.config.validate_hooks_usage {
1681 react_compiler_validation::validate_hooks_usage(hir, env)?;
1682 }
1683 }
1684
1685 react_compiler_optimization::optimize_props_method_calls(hir, env);
1686
1687 react_compiler_inference::analyse_functions(hir, env, &mut |_inner_func, _inner_env| {})?;
1688
1689 if env.has_invariant_errors() {
1690 return Err(env.take_invariant_errors());
1691 }
1692
1693 react_compiler_inference::infer_mutation_aliasing_effects(hir, env, false)?;
1694
1695 if env.output_mode == OutputMode::Ssr {
1696 react_compiler_optimization::optimize_for_ssr(hir, env);
1697 }
1698
1699 react_compiler_optimization::dead_code_elimination(hir, env);
1700
1701 react_compiler_optimization::prune_maybe_throws(hir, &mut env.functions)?;
1702
1703 react_compiler_inference::infer_mutation_aliasing_ranges(hir, env, false)?;
1704
1705 if env.enable_validations() {
1706 react_compiler_validation::validate_locals_not_reassigned_after_render(hir, env);
1707
1708 if env.config.validate_ref_access_during_render {
1709 react_compiler_validation::validate_no_ref_access_in_render(hir, env);
1710 }
1711
1712 if env.config.validate_no_set_state_in_render {
1713 react_compiler_validation::validate_no_set_state_in_render(hir, env)?;
1714 }
1715
1716 react_compiler_validation::validate_no_freezing_known_mutable_functions(hir, env);
1717 }
1718
1719 react_compiler_inference::infer_reactive_places(hir, env)?;
1720
1721 if env.enable_validations() {
1722 react_compiler_validation::validate_exhaustive_dependencies(hir, env)?;
1723 }
1724
1725 react_compiler_ssa::rewrite_instruction_kinds_based_on_reassignment(hir, env)?;
1726
1727 if env.enable_memoization() {
1728 react_compiler_inference::infer_reactive_scope_variables(hir, env)?;
1729 }
1730
1731 let fbt_operands =
1732 react_compiler_inference::memoize_fbt_and_macro_operands_in_same_scope(hir, env);
1733
1734 if env.config.enable_name_anonymous_functions {
1737 react_compiler_optimization::name_anonymous_functions(hir, env);
1738 }
1739
1740 if env.config.enable_function_outlining {
1741 react_compiler_optimization::outline_functions(hir, env, &fbt_operands);
1742 }
1743
1744 react_compiler_inference::align_method_call_scopes(hir, env);
1745 react_compiler_inference::align_object_method_scopes(hir, env);
1746
1747 react_compiler_optimization::prune_unused_labels_hir(hir);
1748
1749 react_compiler_inference::align_reactive_scopes_to_block_scopes_hir(hir, env);
1750 react_compiler_inference::merge_overlapping_reactive_scopes_hir(hir, env);
1751
1752 react_compiler_inference::build_reactive_scope_terminals_hir(hir, env);
1753 react_compiler_inference::flatten_reactive_loops_hir(hir);
1754 react_compiler_inference::flatten_scopes_with_hooks_or_use_hir(hir, env)?;
1755 react_compiler_inference::propagate_scope_dependencies_hir(hir, env);
1756 let mut reactive_fn = react_compiler_reactive_scopes::build_reactive_function(hir, env)?;
1757
1758 react_compiler_reactive_scopes::assert_well_formed_break_targets(&reactive_fn, env);
1759
1760 react_compiler_reactive_scopes::prune_unused_labels(&mut reactive_fn, env)?;
1761
1762 react_compiler_reactive_scopes::assert_scope_instructions_within_scopes(&reactive_fn, env)?;
1763
1764 react_compiler_reactive_scopes::prune_non_escaping_scopes(&mut reactive_fn, env)?;
1765 react_compiler_reactive_scopes::prune_non_reactive_dependencies(&mut reactive_fn, env);
1766 react_compiler_reactive_scopes::prune_unused_scopes(&mut reactive_fn, env)?;
1767 react_compiler_reactive_scopes::merge_reactive_scopes_that_invalidate_together(
1768 &mut reactive_fn,
1769 env,
1770 )?;
1771 react_compiler_reactive_scopes::prune_always_invalidating_scopes(&mut reactive_fn, env)?;
1772 react_compiler_reactive_scopes::propagate_early_returns(&mut reactive_fn, env);
1773 react_compiler_reactive_scopes::prune_unused_lvalues(&mut reactive_fn, env);
1774 react_compiler_reactive_scopes::promote_used_temporaries(&mut reactive_fn, env);
1775 react_compiler_reactive_scopes::extract_scope_declarations_from_destructuring(
1776 &mut reactive_fn,
1777 env,
1778 )?;
1779 react_compiler_reactive_scopes::stabilize_block_ids(&mut reactive_fn, env);
1780
1781 let unique_identifiers =
1782 react_compiler_reactive_scopes::rename_variables(&mut reactive_fn, env);
1783 for name in &unique_identifiers {
1784 context.add_new_reference(name.clone());
1785 }
1786
1787 react_compiler_reactive_scopes::prune_hoisted_contexts(&mut reactive_fn, env)?;
1788
1789 if env.config.enable_preserve_existing_memoization_guarantees
1790 || env.config.validate_preserve_existing_memoization_guarantees
1791 {
1792 react_compiler_validation::validate_preserved_manual_memoization(&reactive_fn, env);
1793 }
1794
1795 let codegen_result = react_compiler_reactive_scopes::codegen_function(
1796 &reactive_fn,
1797 env,
1798 unique_identifiers,
1799 fbt_operands,
1800 )?;
1801
1802 Ok(CodegenFunction {
1803 loc: codegen_result.loc,
1804 id: codegen_result.id,
1805 name_hint: codegen_result.name_hint,
1806 params: codegen_result.params,
1807 body: codegen_result.body,
1808 generator: codegen_result.generator,
1809 is_async: codegen_result.is_async,
1810 memo_slots_used: codegen_result.memo_slots_used,
1811 memo_blocks: codegen_result.memo_blocks,
1812 memo_values: codegen_result.memo_values,
1813 pruned_memo_blocks: codegen_result.pruned_memo_blocks,
1814 pruned_memo_values: codegen_result.pruned_memo_values,
1815 outlined: codegen_result
1816 .outlined
1817 .into_iter()
1818 .map(|o| OutlinedFunction {
1819 func: CodegenFunction {
1820 loc: o.func.loc,
1821 id: o.func.id,
1822 name_hint: o.func.name_hint,
1823 params: o.func.params,
1824 body: o.func.body,
1825 generator: o.func.generator,
1826 is_async: o.func.is_async,
1827 memo_slots_used: o.func.memo_slots_used,
1828 memo_blocks: o.func.memo_blocks,
1829 memo_values: o.func.memo_values,
1830 pruned_memo_blocks: o.func.pruned_memo_blocks,
1831 pruned_memo_values: o.func.pruned_memo_values,
1832 outlined: Vec::new(),
1833 },
1834 fn_type: o.fn_type,
1835 })
1836 .collect(),
1837 })
1838}
1839
1840fn log_errors_as_events(errors: &CompilerError, context: &mut ProgramContext) {
1843 let source_filename = context.source_filename();
1846 for detail in &errors.details {
1847 let detail_info = match detail {
1848 react_compiler_diagnostics::CompilerErrorOrDiagnostic::Diagnostic(d) => {
1849 let items: Option<Vec<CompilerErrorItemInfo>> = {
1850 let v: Vec<CompilerErrorItemInfo> = d
1851 .details
1852 .iter()
1853 .map(|item| match item {
1854 react_compiler_diagnostics::CompilerDiagnosticDetail::Error {
1855 loc,
1856 message,
1857 identifier_name,
1858 } => CompilerErrorItemInfo {
1859 kind: "error".to_string(),
1860 loc: loc.as_ref().map(|l| LoggerSourceLocation {
1861 start: LoggerPosition {
1862 line: l.start.line,
1863 column: l.start.column,
1864 index: l.start.index,
1865 },
1866 end: LoggerPosition {
1867 line: l.end.line,
1868 column: l.end.column,
1869 index: l.end.index,
1870 },
1871 filename: source_filename.clone(),
1872 identifier_name: identifier_name.clone(),
1873 }),
1874 message: message.clone(),
1875 },
1876 react_compiler_diagnostics::CompilerDiagnosticDetail::Hint {
1877 message,
1878 } => CompilerErrorItemInfo {
1879 kind: "hint".to_string(),
1880 loc: None,
1881 message: Some(message.clone()),
1882 },
1883 })
1884 .collect();
1885 if v.is_empty() { None } else { Some(v) }
1886 };
1887 CompilerErrorDetailInfo {
1888 category: format!("{:?}", d.category),
1889 reason: d.reason.clone(),
1890 description: d.description.clone(),
1891 severity: format!("{:?}", d.logged_severity()),
1892 suggestions: None,
1893 details: items,
1894 loc: None,
1895 }
1896 }
1897 react_compiler_diagnostics::CompilerErrorOrDiagnostic::ErrorDetail(d) => {
1898 CompilerErrorDetailInfo {
1899 category: format!("{:?}", d.category),
1900 reason: d.reason.clone(),
1901 description: d.description.clone(),
1902 severity: format!("{:?}", d.logged_severity()),
1903 suggestions: None,
1904 details: None,
1905 loc: None,
1906 }
1907 }
1908 };
1909 context.log_event(super::compile_result::LoggerEvent::CompileError {
1910 fn_loc: None,
1911 detail: detail_info,
1912 });
1913 }
1914}