compiler/crates/react_compiler/src/entrypoint/pipeline.rs RUST 1,915 lines View on github.com → Search inside
1// Copyright (c) Meta Platforms, Inc. and affiliates.2//3// This source code is licensed under the MIT license found in the4// LICENSE file in the root directory of this source tree.56//! Compilation pipeline for a single function.7//!8//! Analogous to TS `Pipeline.ts` (`compileFn` → `run` → `runWithEnvironment`).9//! Currently runs BuildHIR (lowering) and PruneMaybeThrows.1011use indexmap::IndexMap;12use react_compiler_ast::scope::ScopeInfo;13use react_compiler_diagnostics::CompilerError;14use react_compiler_hir::ReactFunctionType;15use react_compiler_hir::environment::Environment;16use react_compiler_hir::environment::OutputMode;17use react_compiler_hir::environment_config::EnvironmentConfig;18use react_compiler_lowering::FunctionNode;19use rustc_hash::{FxBuildHasher, FxHashMap};2021use super::compile_result::CodegenFunction;22use super::compile_result::CompilerErrorDetailInfo;23use super::compile_result::CompilerErrorItemInfo;24use super::compile_result::DebugLogEntry;25use super::compile_result::LoggerPosition;26use super::compile_result::LoggerSourceLocation;27use super::compile_result::OutlinedFunction;28use super::imports::ProgramContext;29use super::plugin_options::CompilerOutputMode;30use crate::debug_print;3132/// Run the compilation pipeline on a single function.33///34/// Currently: creates an Environment, runs BuildHIR (lowering), and produces35/// debug output via the context. Returns a CodegenFunction with zeroed memo36/// stats on success (codegen is not yet implemented).37pub fn compile_fn(38    func: &FunctionNode<'_>,39    fn_name: Option<&str>,40    scope_info: &ScopeInfo,41    fn_type: ReactFunctionType,42    mode: CompilerOutputMode,43    env_config: &EnvironmentConfig,44    context: &mut ProgramContext,45) -> Result<CodegenFunction, CompilerError> {46    let mut env = Environment::with_config(env_config.clone());47    env.fn_type = fn_type;48    env.output_mode = match mode {49        CompilerOutputMode::Ssr => OutputMode::Ssr,50        CompilerOutputMode::Client => OutputMode::Client,51        CompilerOutputMode::Lint => OutputMode::Lint,52    };53    env.code = context.code.clone();54    env.filename = context.filename.clone();55    env.instrument_fn_name = context.instrument_fn_name.clone();56    env.instrument_gating_name = context.instrument_gating_name.clone();57    env.hook_guard_name = context.hook_guard_name.clone();58    env.seed_uid_known_names(&context.known_referenced_names());5960    env.reference_node_ids = scope_info.ref_node_id_to_binding.keys().copied().collect();6162    context.timing.start("lower");63    let mut hir = react_compiler_lowering::lower(func, fn_name, scope_info, &mut env)?;64    context.timing.stop();6566    // Copy renames from lowering to context (keep on env for codegen to apply to type annotations)67    if !env.renames.is_empty() {68        context.renames.extend(env.renames.iter().cloned());69    }7071    // Check for Invariant errors after lowering, before logging HIR.72    // In TS, Invariant errors throw from recordError(), aborting lower() before73    // the HIR entry is logged. The thrown error contains ONLY the Invariant error,74    // not other recorded (non-Invariant) errors.75    if env.has_invariant_errors() {76        return Err(env.take_invariant_errors());77    }7879    if context.debug_enabled {80        context.timing.start("debug_print:HIR");81        let debug_hir = debug_print::debug_hir(&hir, &env);82        context.log_debug(DebugLogEntry::new("HIR", debug_hir));83        context.timing.stop();84    }8586    context.timing.start("PruneMaybeThrows");87    react_compiler_optimization::prune_maybe_throws(&mut hir, &mut env.functions)?;88    context.timing.stop();8990    if context.debug_enabled {91        context.timing.start("debug_print:PruneMaybeThrows");92        let debug_prune = debug_print::debug_hir(&hir, &env);93        context.log_debug(DebugLogEntry::new("PruneMaybeThrows", debug_prune));94        context.timing.stop();95    }9697    context.timing.start("ValidateContextVariableLValues");98    react_compiler_validation::validate_context_variable_lvalues(&hir, &mut env)?;99    if context.debug_enabled {100        context.log_debug(DebugLogEntry::new(101            "ValidateContextVariableLValues",102            "ok".to_string(),103        ));104    }105    context.timing.stop();106107    context.timing.start("ValidateUseMemo");108    let void_memo_errors = react_compiler_validation::validate_use_memo(&hir, &mut env);109    log_errors_as_events(&void_memo_errors, context);110    if context.debug_enabled {111        context.log_debug(DebugLogEntry::new("ValidateUseMemo", "ok".to_string()));112    }113    context.timing.stop();114115    context.timing.start("DropManualMemoization");116    react_compiler_optimization::drop_manual_memoization(&mut hir, &mut env)?;117    context.timing.stop();118119    if context.debug_enabled {120        context.timing.start("debug_print:DropManualMemoization");121        let debug_drop_memo = debug_print::debug_hir(&hir, &env);122        context.log_debug(DebugLogEntry::new("DropManualMemoization", debug_drop_memo));123        context.timing.stop();124    }125126    context127        .timing128        .start("InlineImmediatelyInvokedFunctionExpressions");129    react_compiler_optimization::inline_immediately_invoked_function_expressions(130        &mut hir, &mut env,131    );132    context.timing.stop();133134    if context.debug_enabled {135        context136            .timing137            .start("debug_print:InlineImmediatelyInvokedFunctionExpressions");138        let debug_inline_iifes = debug_print::debug_hir(&hir, &env);139        context.log_debug(DebugLogEntry::new(140            "InlineImmediatelyInvokedFunctionExpressions",141            debug_inline_iifes,142        ));143        context.timing.stop();144    }145146    context.timing.start("MergeConsecutiveBlocks");147    react_compiler_optimization::merge_consecutive_blocks::merge_consecutive_blocks(148        &mut hir,149        &mut env.functions,150    );151    context.timing.stop();152153    if context.debug_enabled {154        context.timing.start("debug_print:MergeConsecutiveBlocks");155        let debug_merge = debug_print::debug_hir(&hir, &env);156        context.log_debug(DebugLogEntry::new("MergeConsecutiveBlocks", debug_merge));157        context.timing.stop();158    }159160    // TODO: port assertConsistentIdentifiers161    if context.debug_enabled {162        context.log_debug(DebugLogEntry::new(163            "AssertConsistentIdentifiers",164            "ok".to_string(),165        ));166    }167    // TODO: port assertTerminalSuccessorsExist168    if context.debug_enabled {169        context.log_debug(DebugLogEntry::new(170            "AssertTerminalSuccessorsExist",171            "ok".to_string(),172        ));173    }174175    context.timing.start("EnterSSA");176    react_compiler_ssa::enter_ssa(&mut hir, &mut env).map_err(|diag| {177        let loc = diag.primary_location().cloned();178        let mut err = CompilerError::new();179        err.push_error_detail(react_compiler_diagnostics::CompilerErrorDetail {180            category: diag.category,181            reason: diag.reason,182            description: diag.description,183            loc,184            suggestions: diag.suggestions,185        });186        err187    })?;188    context.timing.stop();189190    if context.debug_enabled {191        context.timing.start("debug_print:SSA");192        let debug_ssa = debug_print::debug_hir(&hir, &env);193        context.log_debug(DebugLogEntry::new("SSA", debug_ssa));194        context.timing.stop();195    }196197    context.timing.start("EliminateRedundantPhi");198    react_compiler_ssa::eliminate_redundant_phi(&mut hir, &mut env);199    context.timing.stop();200201    if context.debug_enabled {202        context.timing.start("debug_print:EliminateRedundantPhi");203        let debug_eliminate_phi = debug_print::debug_hir(&hir, &env);204        context.log_debug(DebugLogEntry::new(205            "EliminateRedundantPhi",206            debug_eliminate_phi,207        ));208        context.timing.stop();209    }210211    // TODO: port assertConsistentIdentifiers212    if context.debug_enabled {213        context.log_debug(DebugLogEntry::new(214            "AssertConsistentIdentifiers",215            "ok".to_string(),216        ));217    }218219    context.timing.start("ConstantPropagation");220    react_compiler_optimization::constant_propagation(&mut hir, &mut env);221    context.timing.stop();222223    if context.debug_enabled {224        context.timing.start("debug_print:ConstantPropagation");225        let debug_const_prop = debug_print::debug_hir(&hir, &env);226        context.log_debug(DebugLogEntry::new("ConstantPropagation", debug_const_prop));227        context.timing.stop();228    }229230    context.timing.start("InferTypes");231    react_compiler_typeinference::infer_types(&mut hir, &mut env)?;232    context.timing.stop();233234    if context.debug_enabled {235        context.timing.start("debug_print:InferTypes");236        let debug_infer_types = debug_print::debug_hir(&hir, &env);237        context.log_debug(DebugLogEntry::new("InferTypes", debug_infer_types));238        context.timing.stop();239    }240241    if env.enable_validations() {242        if env.config.validate_hooks_usage {243            context.timing.start("ValidateHooksUsage");244            react_compiler_validation::validate_hooks_usage(&hir, &mut env)?;245            if context.debug_enabled {246                context.log_debug(DebugLogEntry::new("ValidateHooksUsage", "ok".to_string()));247            }248            context.timing.stop();249        }250251        if env.config.validate_no_capitalized_calls.is_some() {252            context.timing.start("ValidateNoCapitalizedCalls");253            react_compiler_validation::validate_no_capitalized_calls(&hir, &mut env)?;254            if context.debug_enabled {255                context.log_debug(DebugLogEntry::new(256                    "ValidateNoCapitalizedCalls",257                    "ok".to_string(),258                ));259            }260            context.timing.stop();261        }262    }263264    context.timing.start("OptimizePropsMethodCalls");265    react_compiler_optimization::optimize_props_method_calls(&mut hir, &env);266    context.timing.stop();267268    if context.debug_enabled {269        context.timing.start("debug_print:OptimizePropsMethodCalls");270        let debug_optimize_props = debug_print::debug_hir(&hir, &env);271        context.log_debug(DebugLogEntry::new(272            "OptimizePropsMethodCalls",273            debug_optimize_props,274        ));275        context.timing.stop();276    }277278    context.timing.start("AnalyseFunctions");279    let mut inner_logs: Vec<String> = Vec::new();280    let debug_inner = context.debug_enabled;281    let analyse_result = react_compiler_inference::analyse_functions(282        &mut hir,283        &mut env,284        &mut |inner_func, inner_env| {285            if debug_inner {286                inner_logs.push(debug_print::debug_hir(inner_func, inner_env));287            }288        },289    );290    context.timing.stop();291292    // Always flush inner logs before propagating errors293    if context.debug_enabled {294        for inner_log in inner_logs {295            context.log_debug(DebugLogEntry::new("AnalyseFunction (inner)", inner_log));296        }297    }298299    analyse_result?;300301    if env.has_invariant_errors() {302        return Err(env.take_invariant_errors());303    }304305    if context.debug_enabled {306        context.timing.start("debug_print:AnalyseFunctions");307        let debug_analyse_functions = debug_print::debug_hir(&hir, &env);308        context.log_debug(DebugLogEntry::new(309            "AnalyseFunctions",310            debug_analyse_functions,311        ));312        context.timing.stop();313    }314315    context.timing.start("InferMutationAliasingEffects");316    react_compiler_inference::infer_mutation_aliasing_effects(&mut hir, &mut env, false)?;317    context.timing.stop();318319    if context.debug_enabled {320        context321            .timing322            .start("debug_print:InferMutationAliasingEffects");323        let debug_infer_effects = debug_print::debug_hir(&hir, &env);324        context.log_debug(DebugLogEntry::new(325            "InferMutationAliasingEffects",326            debug_infer_effects,327        ));328        context.timing.stop();329    }330331    if env.output_mode == OutputMode::Ssr {332        context.timing.start("OptimizeForSSR");333        react_compiler_optimization::optimize_for_ssr(&mut hir, &env);334        context.timing.stop();335336        if context.debug_enabled {337            context.timing.start("debug_print:OptimizeForSSR");338            let debug_ssr = debug_print::debug_hir(&hir, &env);339            context.log_debug(DebugLogEntry::new("OptimizeForSSR", debug_ssr));340            context.timing.stop();341        }342    }343344    context.timing.start("DeadCodeElimination");345    react_compiler_optimization::dead_code_elimination(&mut hir, &env);346    context.timing.stop();347348    if context.debug_enabled {349        context.timing.start("debug_print:DeadCodeElimination");350        let debug_dce = debug_print::debug_hir(&hir, &env);351        context.log_debug(DebugLogEntry::new("DeadCodeElimination", debug_dce));352        context.timing.stop();353    }354355    context.timing.start("PruneMaybeThrows2");356    react_compiler_optimization::prune_maybe_throws(&mut hir, &mut env.functions)?;357    context.timing.stop();358359    if context.debug_enabled {360        context.timing.start("debug_print:PruneMaybeThrows2");361        let debug_prune2 = debug_print::debug_hir(&hir, &env);362        context.log_debug(DebugLogEntry::new("PruneMaybeThrows", debug_prune2));363        context.timing.stop();364    }365366    context.timing.start("InferMutationAliasingRanges");367    react_compiler_inference::infer_mutation_aliasing_ranges(&mut hir, &mut env, false)?;368    context.timing.stop();369370    if context.debug_enabled {371        context372            .timing373            .start("debug_print:InferMutationAliasingRanges");374        let debug_infer_ranges = debug_print::debug_hir(&hir, &env);375        context.log_debug(DebugLogEntry::new(376            "InferMutationAliasingRanges",377            debug_infer_ranges,378        ));379        context.timing.stop();380    }381382    if env.enable_validations() {383        context384            .timing385            .start("ValidateLocalsNotReassignedAfterRender");386        react_compiler_validation::validate_locals_not_reassigned_after_render(&hir, &mut env);387        if context.debug_enabled {388            context.log_debug(DebugLogEntry::new(389                "ValidateLocalsNotReassignedAfterRender",390                "ok".to_string(),391            ));392        }393        context.timing.stop();394395        if env.config.validate_ref_access_during_render {396            context.timing.start("ValidateNoRefAccessInRender");397            react_compiler_validation::validate_no_ref_access_in_render(&hir, &mut env);398            if context.debug_enabled {399                context.log_debug(DebugLogEntry::new(400                    "ValidateNoRefAccessInRender",401                    "ok".to_string(),402                ));403            }404            context.timing.stop();405        }406407        if env.config.validate_no_set_state_in_render {408            context.timing.start("ValidateNoSetStateInRender");409            react_compiler_validation::validate_no_set_state_in_render(&hir, &mut env)?;410            if context.debug_enabled {411                context.log_debug(DebugLogEntry::new(412                    "ValidateNoSetStateInRender",413                    "ok".to_string(),414                ));415            }416            context.timing.stop();417        }418419        if env.config.validate_no_derived_computations_in_effects_exp420            && env.output_mode == OutputMode::Lint421        {422            context423                .timing424                .start("ValidateNoDerivedComputationsInEffects");425            let errors =426                react_compiler_validation::validate_no_derived_computations_in_effects_exp(427                    &hir, &env,428                )?;429            log_errors_as_events(&errors, context);430            if context.debug_enabled {431                context.log_debug(DebugLogEntry::new(432                    "ValidateNoDerivedComputationsInEffects",433                    "ok".to_string(),434                ));435            }436            context.timing.stop();437        } else if env.config.validate_no_derived_computations_in_effects {438            context439                .timing440                .start("ValidateNoDerivedComputationsInEffects");441            react_compiler_validation::validate_no_derived_computations_in_effects(&hir, &mut env)?;442            if context.debug_enabled {443                context.log_debug(DebugLogEntry::new(444                    "ValidateNoDerivedComputationsInEffects",445                    "ok".to_string(),446                ));447            }448            context.timing.stop();449        }450451        if env.config.validate_no_set_state_in_effects && env.output_mode == OutputMode::Lint {452            context.timing.start("ValidateNoSetStateInEffects");453            let errors = react_compiler_validation::validate_no_set_state_in_effects(&hir, &env)?;454            log_errors_as_events(&errors, context);455            if context.debug_enabled {456                context.log_debug(DebugLogEntry::new(457                    "ValidateNoSetStateInEffects",458                    "ok".to_string(),459                ));460            }461            context.timing.stop();462        }463464        if env.config.validate_no_jsx_in_try_statements && env.output_mode == OutputMode::Lint {465            context.timing.start("ValidateNoJSXInTryStatement");466            let errors = react_compiler_validation::validate_no_jsx_in_try_statement(&hir);467            log_errors_as_events(&errors, context);468            if context.debug_enabled {469                context.log_debug(DebugLogEntry::new(470                    "ValidateNoJSXInTryStatement",471                    "ok".to_string(),472                ));473            }474            context.timing.stop();475        }476477        context478            .timing479            .start("ValidateNoFreezingKnownMutableFunctions");480        react_compiler_validation::validate_no_freezing_known_mutable_functions(&hir, &mut env);481        if context.debug_enabled {482            context.log_debug(DebugLogEntry::new(483                "ValidateNoFreezingKnownMutableFunctions",484                "ok".to_string(),485            ));486        }487        context.timing.stop();488    }489490    context.timing.start("InferReactivePlaces");491    react_compiler_inference::infer_reactive_places(&mut hir, &mut env)?;492    context.timing.stop();493494    if context.debug_enabled {495        context.timing.start("debug_print:InferReactivePlaces");496        let debug_reactive_places = debug_print::debug_hir(&hir, &env);497        context.log_debug(DebugLogEntry::new(498            "InferReactivePlaces",499            debug_reactive_places,500        ));501        context.timing.stop();502    }503504    if env.enable_validations() {505        context.timing.start("ValidateExhaustiveDependencies");506        react_compiler_validation::validate_exhaustive_dependencies(&mut hir, &mut env)?;507        if context.debug_enabled {508            context.log_debug(DebugLogEntry::new(509                "ValidateExhaustiveDependencies",510                "ok".to_string(),511            ));512        }513        context.timing.stop();514    }515516    context517        .timing518        .start("RewriteInstructionKindsBasedOnReassignment");519    react_compiler_ssa::rewrite_instruction_kinds_based_on_reassignment(&mut hir, &env)?;520    context.timing.stop();521522    if context.debug_enabled {523        context524            .timing525            .start("debug_print:RewriteInstructionKindsBasedOnReassignment");526        let debug_rewrite = debug_print::debug_hir(&hir, &env);527        context.log_debug(DebugLogEntry::new(528            "RewriteInstructionKindsBasedOnReassignment",529            debug_rewrite,530        ));531        context.timing.stop();532    }533534    if env.enable_validations()535        && env.config.validate_static_components536        && env.output_mode == OutputMode::Lint537    {538        context.timing.start("ValidateStaticComponents");539        let errors = react_compiler_validation::validate_static_components(&hir);540        log_errors_as_events(&errors, context);541        if context.debug_enabled {542            context.log_debug(DebugLogEntry::new(543                "ValidateStaticComponents",544                "ok".to_string(),545            ));546        }547        context.timing.stop();548    }549550    if env.enable_memoization() {551        context.timing.start("InferReactiveScopeVariables");552        react_compiler_inference::infer_reactive_scope_variables(&mut hir, &mut env)?;553        context.timing.stop();554555        if context.debug_enabled {556            context557                .timing558                .start("debug_print:InferReactiveScopeVariables");559            let debug_infer_scopes = debug_print::debug_hir(&hir, &env);560            context.log_debug(DebugLogEntry::new(561                "InferReactiveScopeVariables",562                debug_infer_scopes,563            ));564            context.timing.stop();565        }566    }567568    context569        .timing570        .start("MemoizeFbtAndMacroOperandsInSameScope");571    let fbt_operands =572        react_compiler_inference::memoize_fbt_and_macro_operands_in_same_scope(&hir, &mut env);573    context.timing.stop();574575    if context.debug_enabled {576        context577            .timing578            .start("debug_print:MemoizeFbtAndMacroOperandsInSameScope");579        let debug_fbt = debug_print::debug_hir(&hir, &env);580        context.log_debug(DebugLogEntry::new(581            "MemoizeFbtAndMacroOperandsInSameScope",582            debug_fbt,583        ));584        context.timing.stop();585    }586587    if env.config.enable_jsx_outlining {588        context.timing.start("OutlineJsx");589        react_compiler_optimization::outline_jsx(&mut hir, &mut env);590        context.timing.stop();591    }592593    if env.config.enable_name_anonymous_functions {594        context.timing.start("NameAnonymousFunctions");595        react_compiler_optimization::name_anonymous_functions(&mut hir, &mut env);596        context.timing.stop();597598        if context.debug_enabled {599            context.timing.start("debug_print:NameAnonymousFunctions");600            let debug_name_anon = debug_print::debug_hir(&hir, &env);601            context.log_debug(DebugLogEntry::new(602                "NameAnonymousFunctions",603                debug_name_anon,604            ));605            context.timing.stop();606        }607    }608609    if env.config.enable_function_outlining {610        context.timing.start("OutlineFunctions");611        react_compiler_optimization::outline_functions(&mut hir, &mut env, &fbt_operands);612        context.timing.stop();613614        if context.debug_enabled {615            context.timing.start("debug_print:OutlineFunctions");616            let debug_outline = debug_print::debug_hir(&hir, &env);617            context.log_debug(DebugLogEntry::new("OutlineFunctions", debug_outline));618            context.timing.stop();619        }620    }621622    context.timing.start("AlignMethodCallScopes");623    react_compiler_inference::align_method_call_scopes(&mut hir, &mut env);624    context.timing.stop();625626    if context.debug_enabled {627        context.timing.start("debug_print:AlignMethodCallScopes");628        let debug_align = debug_print::debug_hir(&hir, &env);629        context.log_debug(DebugLogEntry::new("AlignMethodCallScopes", debug_align));630        context.timing.stop();631    }632633    context.timing.start("AlignObjectMethodScopes");634    react_compiler_inference::align_object_method_scopes(&mut hir, &mut env);635    context.timing.stop();636637    if context.debug_enabled {638        context.timing.start("debug_print:AlignObjectMethodScopes");639        let debug_align_obj = debug_print::debug_hir(&hir, &env);640        context.log_debug(DebugLogEntry::new(641            "AlignObjectMethodScopes",642            debug_align_obj,643        ));644        context.timing.stop();645    }646647    context.timing.start("PruneUnusedLabelsHIR");648    react_compiler_optimization::prune_unused_labels_hir(&mut hir);649    context.timing.stop();650651    if context.debug_enabled {652        context.timing.start("debug_print:PruneUnusedLabelsHIR");653        let debug_prune_labels = debug_print::debug_hir(&hir, &env);654        context.log_debug(DebugLogEntry::new(655            "PruneUnusedLabelsHIR",656            debug_prune_labels,657        ));658        context.timing.stop();659    }660661    context.timing.start("AlignReactiveScopesToBlockScopesHIR");662    react_compiler_inference::align_reactive_scopes_to_block_scopes_hir(&mut hir, &mut env);663    context.timing.stop();664665    if context.debug_enabled {666        context667            .timing668            .start("debug_print:AlignReactiveScopesToBlockScopesHIR");669        let debug_align_block_scopes = debug_print::debug_hir(&hir, &env);670        context.log_debug(DebugLogEntry::new(671            "AlignReactiveScopesToBlockScopesHIR",672            debug_align_block_scopes,673        ));674        context.timing.stop();675    }676677    context.timing.start("MergeOverlappingReactiveScopesHIR");678    react_compiler_inference::merge_overlapping_reactive_scopes_hir(&mut hir, &mut env);679    context.timing.stop();680681    if context.debug_enabled {682        context683            .timing684            .start("debug_print:MergeOverlappingReactiveScopesHIR");685        let debug_merge_overlapping = debug_print::debug_hir(&hir, &env);686        context.log_debug(DebugLogEntry::new(687            "MergeOverlappingReactiveScopesHIR",688            debug_merge_overlapping,689        ));690        context.timing.stop();691    }692693    // TODO: port assertValidBlockNesting694    if context.debug_enabled {695        context.log_debug(DebugLogEntry::new(696            "AssertValidBlockNesting",697            "ok".to_string(),698        ));699    }700701    context.timing.start("BuildReactiveScopeTerminalsHIR");702    react_compiler_inference::build_reactive_scope_terminals_hir(&mut hir, &mut env);703    context.timing.stop();704705    if context.debug_enabled {706        context707            .timing708            .start("debug_print:BuildReactiveScopeTerminalsHIR");709        let debug_build_scope_terminals = debug_print::debug_hir(&hir, &env);710        context.log_debug(DebugLogEntry::new(711            "BuildReactiveScopeTerminalsHIR",712            debug_build_scope_terminals,713        ));714        context.timing.stop();715    }716717    // TODO: port assertValidBlockNesting718    if context.debug_enabled {719        context.log_debug(DebugLogEntry::new(720            "AssertValidBlockNesting",721            "ok".to_string(),722        ));723    }724725    context.timing.start("FlattenReactiveLoopsHIR");726    react_compiler_inference::flatten_reactive_loops_hir(&mut hir);727    context.timing.stop();728729    if context.debug_enabled {730        context.timing.start("debug_print:FlattenReactiveLoopsHIR");731        let debug_flatten_loops = debug_print::debug_hir(&hir, &env);732        context.log_debug(DebugLogEntry::new(733            "FlattenReactiveLoopsHIR",734            debug_flatten_loops,735        ));736        context.timing.stop();737    }738739    context.timing.start("FlattenScopesWithHooksOrUseHIR");740    react_compiler_inference::flatten_scopes_with_hooks_or_use_hir(&mut hir, &env)?;741    context.timing.stop();742743    if context.debug_enabled {744        context745            .timing746            .start("debug_print:FlattenScopesWithHooksOrUseHIR");747        let debug_flatten_hooks = debug_print::debug_hir(&hir, &env);748        context.log_debug(DebugLogEntry::new(749            "FlattenScopesWithHooksOrUseHIR",750            debug_flatten_hooks,751        ));752        context.timing.stop();753    }754755    // TODO: port assertTerminalSuccessorsExist756    if context.debug_enabled {757        context.log_debug(DebugLogEntry::new(758            "AssertTerminalSuccessorsExist",759            "ok".to_string(),760        ));761    }762    // TODO: port assertTerminalPredsExist763    if context.debug_enabled {764        context.log_debug(DebugLogEntry::new(765            "AssertTerminalPredsExist",766            "ok".to_string(),767        ));768    }769770    context.timing.start("PropagateScopeDependenciesHIR");771    react_compiler_inference::propagate_scope_dependencies_hir(&mut hir, &mut env);772    context.timing.stop();773774    if context.debug_enabled {775        context776            .timing777            .start("debug_print:PropagateScopeDependenciesHIR");778        let debug_propagate_deps = debug_print::debug_hir(&hir, &env);779        context.log_debug(DebugLogEntry::new(780            "PropagateScopeDependenciesHIR",781            debug_propagate_deps,782        ));783        context.timing.stop();784    }785786    context.timing.start("BuildReactiveFunction");787    let mut reactive_fn = react_compiler_reactive_scopes::build_reactive_function(&hir, &env)?;788    context.timing.stop();789790    let hir_formatter = |fmt: &mut react_compiler_hir::print::PrintFormatter,791                         func: &react_compiler_hir::HirFunction| {792        debug_print::format_hir_function_into(fmt, func);793    };794795    if context.debug_enabled {796        context.timing.start("debug_print:BuildReactiveFunction");797        let debug_reactive = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(798            &reactive_fn, &env, Some(&hir_formatter),799        );800        context.log_debug(DebugLogEntry::new("BuildReactiveFunction", debug_reactive));801        context.timing.stop();802    }803804    context.timing.start("AssertWellFormedBreakTargets");805    react_compiler_reactive_scopes::assert_well_formed_break_targets(&reactive_fn, &env);806    if context.debug_enabled {807        context.log_debug(DebugLogEntry::new(808            "AssertWellFormedBreakTargets",809            "ok".to_string(),810        ));811    }812    context.timing.stop();813814    context.timing.start("PruneUnusedLabels");815    react_compiler_reactive_scopes::prune_unused_labels(&mut reactive_fn, &env)?;816    context.timing.stop();817818    if context.debug_enabled {819        context.timing.start("debug_print:PruneUnusedLabels");820        let debug_prune_labels_reactive = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(821            &reactive_fn, &env, Some(&hir_formatter),822        );823        context.log_debug(DebugLogEntry::new(824            "PruneUnusedLabels",825            debug_prune_labels_reactive,826        ));827        context.timing.stop();828    }829830    context.timing.start("AssertScopeInstructionsWithinScopes");831    react_compiler_reactive_scopes::assert_scope_instructions_within_scopes(&reactive_fn, &env)?;832    if context.debug_enabled {833        context.log_debug(DebugLogEntry::new(834            "AssertScopeInstructionsWithinScopes",835            "ok".to_string(),836        ));837    }838    context.timing.stop();839840    context.timing.start("PruneNonEscapingScopes");841    react_compiler_reactive_scopes::prune_non_escaping_scopes(&mut reactive_fn, &mut env)?;842    context.timing.stop();843844    if context.debug_enabled {845        context.timing.start("debug_print:PruneNonEscapingScopes");846        let debug = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(847            &reactive_fn, &env, Some(&hir_formatter),848        );849        context.log_debug(DebugLogEntry::new("PruneNonEscapingScopes", debug));850        context.timing.stop();851    }852853    context.timing.start("PruneNonReactiveDependencies");854    react_compiler_reactive_scopes::prune_non_reactive_dependencies(&mut reactive_fn, &mut env);855    context.timing.stop();856857    if context.debug_enabled {858        context859            .timing860            .start("debug_print:PruneNonReactiveDependencies");861        let debug_prune_non_reactive = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(862            &reactive_fn, &env, Some(&hir_formatter),863        );864        context.log_debug(DebugLogEntry::new(865            "PruneNonReactiveDependencies",866            debug_prune_non_reactive,867        ));868        context.timing.stop();869    }870871    context.timing.start("PruneUnusedScopes");872    react_compiler_reactive_scopes::prune_unused_scopes(&mut reactive_fn, &env)?;873    context.timing.stop();874875    if context.debug_enabled {876        context.timing.start("debug_print:PruneUnusedScopes");877        let debug_prune_unused_scopes = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(878            &reactive_fn, &env, Some(&hir_formatter),879        );880        context.log_debug(DebugLogEntry::new(881            "PruneUnusedScopes",882            debug_prune_unused_scopes,883        ));884        context.timing.stop();885    }886887    context888        .timing889        .start("MergeReactiveScopesThatInvalidateTogether");890    react_compiler_reactive_scopes::merge_reactive_scopes_that_invalidate_together(891        &mut reactive_fn,892        &mut env,893    )?;894    context.timing.stop();895896    if context.debug_enabled {897        context898            .timing899            .start("debug_print:MergeReactiveScopesThatInvalidateTogether");900        let debug = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(901            &reactive_fn, &env, Some(&hir_formatter),902        );903        context.log_debug(DebugLogEntry::new(904            "MergeReactiveScopesThatInvalidateTogether",905            debug,906        ));907        context.timing.stop();908    }909910    context.timing.start("PruneAlwaysInvalidatingScopes");911    react_compiler_reactive_scopes::prune_always_invalidating_scopes(&mut reactive_fn, &env)?;912    context.timing.stop();913914    if context.debug_enabled {915        context916            .timing917            .start("debug_print:PruneAlwaysInvalidatingScopes");918        let debug_prune_always_inv = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(919            &reactive_fn, &env, Some(&hir_formatter),920        );921        context.log_debug(DebugLogEntry::new(922            "PruneAlwaysInvalidatingScopes",923            debug_prune_always_inv,924        ));925        context.timing.stop();926    }927928    context.timing.start("PropagateEarlyReturns");929    react_compiler_reactive_scopes::propagate_early_returns(&mut reactive_fn, &mut env);930    context.timing.stop();931932    if context.debug_enabled {933        context.timing.start("debug_print:PropagateEarlyReturns");934        let debug = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(935            &reactive_fn, &env, Some(&hir_formatter),936        );937        context.log_debug(DebugLogEntry::new("PropagateEarlyReturns", debug));938        context.timing.stop();939    }940941    context.timing.start("PruneUnusedLValues");942    react_compiler_reactive_scopes::prune_unused_lvalues(&mut reactive_fn, &env);943    context.timing.stop();944945    if context.debug_enabled {946        context.timing.start("debug_print:PruneUnusedLValues");947        let debug_prune_lvalues = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(948            &reactive_fn, &env, Some(&hir_formatter),949        );950        context.log_debug(DebugLogEntry::new(951            "PruneUnusedLValues",952            debug_prune_lvalues,953        ));954        context.timing.stop();955    }956957    context.timing.start("PromoteUsedTemporaries");958    react_compiler_reactive_scopes::promote_used_temporaries(&mut reactive_fn, &mut env);959    context.timing.stop();960961    if context.debug_enabled {962        context.timing.start("debug_print:PromoteUsedTemporaries");963        let debug = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(964            &reactive_fn, &env, Some(&hir_formatter),965        );966        context.log_debug(DebugLogEntry::new("PromoteUsedTemporaries", debug));967        context.timing.stop();968    }969970    context971        .timing972        .start("ExtractScopeDeclarationsFromDestructuring");973    react_compiler_reactive_scopes::extract_scope_declarations_from_destructuring(974        &mut reactive_fn,975        &mut env,976    )?;977    context.timing.stop();978979    if context.debug_enabled {980        context981            .timing982            .start("debug_print:ExtractScopeDeclarationsFromDestructuring");983        let debug = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(984            &reactive_fn, &env, Some(&hir_formatter),985        );986        context.log_debug(DebugLogEntry::new(987            "ExtractScopeDeclarationsFromDestructuring",988            debug,989        ));990        context.timing.stop();991    }992993    context.timing.start("StabilizeBlockIds");994    react_compiler_reactive_scopes::stabilize_block_ids(&mut reactive_fn, &mut env);995    context.timing.stop();996997    if context.debug_enabled {998        context.timing.start("debug_print:StabilizeBlockIds");999        let debug_stabilize = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(1000            &reactive_fn, &env, Some(&hir_formatter),1001        );1002        context.log_debug(DebugLogEntry::new("StabilizeBlockIds", debug_stabilize));1003        context.timing.stop();1004    }10051006    context.timing.start("RenameVariables");1007    let unique_identifiers =1008        react_compiler_reactive_scopes::rename_variables(&mut reactive_fn, &mut env);1009    context.timing.stop();10101011    for name in &unique_identifiers {1012        context.add_new_reference(name.clone());1013    }10141015    if context.debug_enabled {1016        context.timing.start("debug_print:RenameVariables");1017        let debug = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(1018            &reactive_fn, &env, Some(&hir_formatter),1019        );1020        context.log_debug(DebugLogEntry::new("RenameVariables", debug));1021        context.timing.stop();1022    }10231024    context.timing.start("PruneHoistedContexts");1025    react_compiler_reactive_scopes::prune_hoisted_contexts(&mut reactive_fn, &mut env)?;1026    context.timing.stop();10271028    if context.debug_enabled {1029        context.timing.start("debug_print:PruneHoistedContexts");1030        let debug = react_compiler_reactive_scopes::print_reactive_function::debug_reactive_function_with_formatter(1031            &reactive_fn, &env, Some(&hir_formatter),1032        );1033        context.log_debug(DebugLogEntry::new("PruneHoistedContexts", debug));1034        context.timing.stop();1035    }10361037    if env.config.enable_preserve_existing_memoization_guarantees1038        || env.config.validate_preserve_existing_memoization_guarantees1039    {1040        context.timing.start("ValidatePreservedManualMemoization");1041        react_compiler_validation::validate_preserved_manual_memoization(&reactive_fn, &mut env);1042        if context.debug_enabled {1043            context.log_debug(DebugLogEntry::new(1044                "ValidatePreservedManualMemoization",1045                "ok".to_string(),1046            ));1047        }1048        context.timing.stop();1049    }10501051    context.timing.start("codegen");1052    let codegen_result = react_compiler_reactive_scopes::codegen_function(1053        &reactive_fn,1054        &mut env,1055        unique_identifiers,1056        fbt_operands,1057    )?;1058    context.timing.stop();10591060    // NOTE: we intentionally do NOT register the memo cache import here.1061    // The import is registered in apply_compiled_functions() only for functions1062    // that are actually applied to the output. Registering it here would cause1063    // a spurious `import { c as _c }` when a function compiles with memo slots1064    // but is later discarded (e.g., due to "use no memo" opt-out or errors),1065    // while other functions in the same file compile to 0 memo slots.10661067    if env.config.validate_source_locations {1068        super::validate_source_locations::validate_source_locations(1069            func,1070            &codegen_result,1071            &mut env,1072        );1073    }10741075    // Simulate unexpected exception for testing (matches TS Pipeline.ts)1076    if env.config.throw_unknown_exception_testonly {1077        let mut err = CompilerError::new();1078        err.push_error_detail(react_compiler_diagnostics::CompilerErrorDetail {1079            category: react_compiler_diagnostics::ErrorCategory::Invariant,1080            reason: "unexpected error".to_string(),1081            description: None,1082            loc: None,1083            suggestions: None,1084        });1085        return Err(err);1086    }10871088    // Check for accumulated errors at the end of the pipeline1089    // (matches TS Pipeline.ts: env.hasErrors() → Err at the end)1090    if env.has_errors() {1091        // Merge UIDs even on error: in TS, Babel's scope.generateUid() permanently1092        // registers names in the scope's `uids` map regardless of whether the function1093        // compilation succeeds or fails. Without this merge, failed compilations would1094        // "leak" _temp names that subsequent successful compilations wouldn't see,1095        // causing numbering mismatches vs TS.1096        if let Some(uid_names) = env.take_uid_known_names() {1097            context.merge_uid_known_names(&uid_names);1098        }1099        return Err(env.take_errors());1100    }11011102    // Re-compile outlined functions through the full pipeline.1103    // This mirrors TS behavior where outlined functions from JSX outlining1104    // are pushed back onto the compilation queue and compiled as components.1105    let mut compiled_outlined: Vec<OutlinedFunction> = Vec::new();1106    for o in codegen_result.outlined {1107        let outlined_codegen = CodegenFunction {1108            loc: o.func.loc,1109            id: o.func.id,1110            name_hint: o.func.name_hint,1111            params: o.func.params,1112            body: o.func.body,1113            generator: o.func.generator,1114            is_async: o.func.is_async,1115            memo_slots_used: o.func.memo_slots_used,1116            memo_blocks: o.func.memo_blocks,1117            memo_values: o.func.memo_values,1118            pruned_memo_blocks: o.func.pruned_memo_blocks,1119            pruned_memo_values: o.func.pruned_memo_values,1120            outlined: Vec::new(),1121        };1122        if let Some(fn_type) = o.fn_type {1123            let fn_name = outlined_codegen.id.as_ref().map(|id| id.name.clone());1124            match compile_outlined_fn(1125                outlined_codegen,1126                fn_name.as_deref(),1127                fn_type,1128                mode,1129                env_config,1130                context,1131            ) {1132                Ok(compiled) => {1133                    compiled_outlined.push(OutlinedFunction {1134                        func: compiled,1135                        fn_type: Some(fn_type),1136                    });1137                }1138                Err(_err) => {1139                    // If re-compilation fails, skip the outlined function1140                }1141            }1142        } else {1143            compiled_outlined.push(OutlinedFunction {1144                func: outlined_codegen,1145                fn_type: o.fn_type,1146            });1147        }1148    }11491150    if let Some(uid_names) = env.take_uid_known_names() {1151        context.merge_uid_known_names(&uid_names);1152    }11531154    Ok(CodegenFunction {1155        loc: codegen_result.loc,1156        id: codegen_result.id,1157        name_hint: codegen_result.name_hint,1158        params: codegen_result.params,1159        body: codegen_result.body,1160        generator: codegen_result.generator,1161        is_async: codegen_result.is_async,1162        memo_slots_used: codegen_result.memo_slots_used,1163        memo_blocks: codegen_result.memo_blocks,1164        memo_values: codegen_result.memo_values,1165        pruned_memo_blocks: codegen_result.pruned_memo_blocks,1166        pruned_memo_values: codegen_result.pruned_memo_values,1167        outlined: compiled_outlined,1168    })1169}11701171/// Compile an outlined function's codegen AST through the full pipeline.1172///1173/// Creates a fresh Environment, builds a synthetic ScopeInfo with unique fake1174/// positions for identifier resolution, lowers from AST to HIR, then runs1175/// the full compilation pipeline. This mirrors the TS behavior where outlined1176/// functions are inserted into the program AST and re-compiled from scratch.1177pub fn compile_outlined_fn(1178    mut codegen_fn: CodegenFunction,1179    fn_name: Option<&str>,1180    fn_type: ReactFunctionType,1181    mode: CompilerOutputMode,1182    env_config: &EnvironmentConfig,1183    context: &mut ProgramContext,1184) -> Result<CodegenFunction, CompilerError> {1185    let mut env = Environment::with_config(env_config.clone());1186    env.fn_type = fn_type;1187    env.output_mode = match mode {1188        CompilerOutputMode::Ssr => OutputMode::Ssr,1189        CompilerOutputMode::Client => OutputMode::Client,1190        CompilerOutputMode::Lint => OutputMode::Lint,1191    };11921193    // Build a FunctionDeclaration from the codegen output1194    let mut outlined_decl = react_compiler_ast::statements::FunctionDeclaration {1195        base: react_compiler_ast::common::BaseNode::typed("FunctionDeclaration"),1196        id: codegen_fn.id.take(),1197        params: std::mem::take(&mut codegen_fn.params),1198        body: std::mem::replace(1199            &mut codegen_fn.body,1200            react_compiler_ast::statements::BlockStatement {1201                base: react_compiler_ast::common::BaseNode::typed("BlockStatement"),1202                body: Vec::new(),1203                directives: Vec::new(),1204            },1205        ),1206        generator: codegen_fn.generator,1207        is_async: codegen_fn.is_async,1208        declare: None,1209        return_type: None,1210        type_parameters: None,1211        predicate: None,1212        component_declaration: false,1213        hook_declaration: false,1214    };12151216    // Build scope info by assigning fake positions to all identifiers1217    let scope_info = build_outlined_scope_info(&mut outlined_decl);12181219    let func_node = react_compiler_lowering::FunctionNode::FunctionDeclaration(&outlined_decl);1220    let mut hir = react_compiler_lowering::lower(&func_node, fn_name, &scope_info, &mut env)?;12211222    if env.has_invariant_errors() {1223        return Err(env.take_invariant_errors());1224    }12251226    run_pipeline_passes(&mut hir, &mut env, context)1227}12281229/// Build a ScopeInfo for an outlined function declaration by assigning unique1230/// fake positions to all Identifier nodes and building the binding/reference maps.1231fn build_outlined_scope_info(1232    func: &mut react_compiler_ast::statements::FunctionDeclaration,1233) -> react_compiler_ast::scope::ScopeInfo {1234    use react_compiler_ast::scope::*;12351236    let mut pos: u32 = 1; // reserve 0 for the function itself1237    func.base.start = Some(0);12381239    let mut fn_bindings: FxHashMap<String, BindingId> = FxHashMap::default();1240    let mut bindings_list: Vec<BindingData> = Vec::new();1241    let mut ref_to_binding: IndexMap<u32, BindingId, FxBuildHasher> = IndexMap::default();12421243    // Helper to add a binding1244    let _add_binding =1245        |name: &str,1246         kind: BindingKind,1247         p: u32,1248         fn_bindings: &mut FxHashMap<String, BindingId>,1249         bindings_list: &mut Vec<BindingData>,1250         ref_to_binding: &mut IndexMap<u32, BindingId, FxBuildHasher>| {1251            if fn_bindings.contains_key(name) {1252                // Already exists, just add reference1253                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        };12711272    // Process params - add as Param bindings1273    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    }12831284    // Process body - walk all statements to assign positions and collect variable declarations1285    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    }12941295    let program_scope = ScopeData {1296        id: ScopeId(0),1297        parent: None,1298        kind: ScopeKind::Program,1299        bindings: FxHashMap::default(),1300    };1301    let fn_scope = ScopeData {1302        id: ScopeId(1),1303        parent: Some(ScopeId(0)),1304        kind: ScopeKind::Function,1305        bindings: fn_bindings,1306    };13071308    let mut node_to_scope: FxHashMap<u32, ScopeId> = FxHashMap::default();1309    node_to_scope.insert(0, ScopeId(1));13101311    // Mirror position maps into node-ID maps for outlined functions1312    let mut node_id_to_scope: FxHashMap<u32, ScopeId> = FxHashMap::default();1313    node_id_to_scope.insert(0, ScopeId(1));1314    let ref_node_id_to_binding: IndexMap<u32, BindingId, FxBuildHasher> =1315        ref_to_binding.iter().map(|(&k, &v)| (k, v)).collect();13161317    ScopeInfo {1318        scopes: vec![program_scope, fn_scope],1319        bindings: bindings_list,1320        node_to_scope,1321        node_to_scope_end: FxHashMap::default(),1322        reference_to_binding: IndexMap::default(),1323        ref_node_id_to_binding,1324        node_id_to_scope,1325        program_scope: ScopeId(0),1326    }1327}13281329/// Assign positions to identifiers in a pattern and register as bindings.1330fn 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 rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,1335    bindings_list: &mut Vec<react_compiler_ast::scope::BindingData>,1336    ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,1337) {1338    use react_compiler_ast::patterns::PatternLike;1339    use react_compiler_ast::scope::*;13401341    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            // Add as a binding1348            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}14301431/// Assign positions to identifiers in a statement body.1432fn outlined_assign_stmt_positions(1433    stmt: &mut react_compiler_ast::statements::Statement,1434    pos: &mut u32,1435    fn_bindings: &mut rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,1436    bindings_list: &mut Vec<react_compiler_ast::scope::BindingData>,1437    ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,1438) {1439    use react_compiler_ast::statements::Statement;14401441    match stmt {1442        Statement::VariableDeclaration(decl) => {1443            for declarator in &mut decl.declarations {1444                // Process init first (references)1445                if let Some(init) = &mut declarator.init {1446                    outlined_assign_expr_positions(init, pos, fn_bindings, ref_to_binding);1447                }1448                // Process pattern (declarations)1449                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}14751476/// Assign positions to identifiers in an expression.1477fn outlined_assign_expr_positions(1478    expr: &mut react_compiler_ast::expressions::Expression,1479    pos: &mut u32,1480    fn_bindings: &rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,1481    ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,1482) {1483    use react_compiler_ast::expressions::*;14841485    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            // Opening tag1497            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}15371538fn outlined_assign_jsx_name_positions(1539    name: &mut react_compiler_ast::jsx::JSXElementName,1540    pos: &mut u32,1541    fn_bindings: &rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,1542    ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,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}15601561fn outlined_assign_jsx_member_positions(1562    member: &mut react_compiler_ast::jsx::JSXMemberExpression,1563    pos: &mut u32,1564    fn_bindings: &rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,1565    ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,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}15821583fn outlined_assign_jsx_val_positions(1584    val: &mut react_compiler_ast::jsx::JSXAttributeValue,1585    pos: &mut u32,1586    fn_bindings: &rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,1587    ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,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.expression1593            {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}16071608fn outlined_assign_jsx_child_positions(1609    child: &mut react_compiler_ast::jsx::JSXChild,1610    pos: &mut u32,1611    fn_bindings: &rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,1612    ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,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.expression1618            {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}1638// end of outlined function helpers16391640/// Run the compilation pipeline passes on an HIR function (everything after lowering).1641///1642/// This is extracted from `compile_fn` to allow reuse for outlined functions.1643/// Returns the compiled CodegenFunction on success.1644fn 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)?;16501651    react_compiler_optimization::drop_manual_memoization(hir, env)?;16521653    react_compiler_optimization::inline_immediately_invoked_function_expressions(hir, env);16541655    react_compiler_optimization::merge_consecutive_blocks::merge_consecutive_blocks(1656        hir,1657        &mut env.functions,1658    );16591660    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        err1671    })?;16721673    react_compiler_ssa::eliminate_redundant_phi(hir, env);16741675    react_compiler_optimization::constant_propagation(hir, env);16761677    react_compiler_typeinference::infer_types(hir, env)?;16781679    if env.enable_validations() {1680        if env.config.validate_hooks_usage {1681            react_compiler_validation::validate_hooks_usage(hir, env)?;1682        }1683    }16841685    react_compiler_optimization::optimize_props_method_calls(hir, env);16861687    react_compiler_inference::analyse_functions(hir, env, &mut |_inner_func, _inner_env| {})?;16881689    if env.has_invariant_errors() {1690        return Err(env.take_invariant_errors());1691    }16921693    react_compiler_inference::infer_mutation_aliasing_effects(hir, env, false)?;16941695    if env.output_mode == OutputMode::Ssr {1696        react_compiler_optimization::optimize_for_ssr(hir, env);1697    }16981699    react_compiler_optimization::dead_code_elimination(hir, env);17001701    react_compiler_optimization::prune_maybe_throws(hir, &mut env.functions)?;17021703    react_compiler_inference::infer_mutation_aliasing_ranges(hir, env, false)?;17041705    if env.enable_validations() {1706        react_compiler_validation::validate_locals_not_reassigned_after_render(hir, env);17071708        if env.config.validate_ref_access_during_render {1709            react_compiler_validation::validate_no_ref_access_in_render(hir, env);1710        }17111712        if env.config.validate_no_set_state_in_render {1713            react_compiler_validation::validate_no_set_state_in_render(hir, env)?;1714        }17151716        react_compiler_validation::validate_no_freezing_known_mutable_functions(hir, env);1717    }17181719    react_compiler_inference::infer_reactive_places(hir, env)?;17201721    if env.enable_validations() {1722        react_compiler_validation::validate_exhaustive_dependencies(hir, env)?;1723    }17241725    react_compiler_ssa::rewrite_instruction_kinds_based_on_reassignment(hir, env)?;17261727    if env.enable_memoization() {1728        react_compiler_inference::infer_reactive_scope_variables(hir, env)?;1729    }17301731    let fbt_operands =1732        react_compiler_inference::memoize_fbt_and_macro_operands_in_same_scope(hir, env);17331734    // Don't run outline_jsx on outlined functions (they're already outlined)17351736    if env.config.enable_name_anonymous_functions {1737        react_compiler_optimization::name_anonymous_functions(hir, env);1738    }17391740    if env.config.enable_function_outlining {1741        react_compiler_optimization::outline_functions(hir, env, &fbt_operands);1742    }17431744    react_compiler_inference::align_method_call_scopes(hir, env);1745    react_compiler_inference::align_object_method_scopes(hir, env);17461747    react_compiler_optimization::prune_unused_labels_hir(hir);17481749    react_compiler_inference::align_reactive_scopes_to_block_scopes_hir(hir, env);1750    react_compiler_inference::merge_overlapping_reactive_scopes_hir(hir, env);17511752    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)?;17571758    react_compiler_reactive_scopes::assert_well_formed_break_targets(&reactive_fn, env);17591760    react_compiler_reactive_scopes::prune_unused_labels(&mut reactive_fn, env)?;17611762    react_compiler_reactive_scopes::assert_scope_instructions_within_scopes(&reactive_fn, env)?;17631764    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);17801781    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    }17861787    react_compiler_reactive_scopes::prune_hoisted_contexts(&mut reactive_fn, env)?;17881789    if env.config.enable_preserve_existing_memoization_guarantees1790        || env.config.validate_preserve_existing_memoization_guarantees1791    {1792        react_compiler_validation::validate_preserved_manual_memoization(&reactive_fn, env);1793    }17941795    let codegen_result = react_compiler_reactive_scopes::codegen_function(1796        &reactive_fn,1797        env,1798        unique_identifiers,1799        fbt_operands,1800    )?;18011802    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_result1816            .outlined1817            .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}18391840/// Log CompilerError diagnostics as CompileError events, matching TS `env.logErrors()` behavior.1841/// These are logged for telemetry/lint output but not accumulated as compile errors.1842fn log_errors_as_events(errors: &CompilerError, context: &mut ProgramContext) {1843    // Use the source_filename from the AST (set by parser's sourceFilename option).1844    // This is stored on the Environment during lowering.1845    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> = d1851                        .details1852                        .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}

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.