compiler/crates/react_compiler_optimization/src/outline_functions.rs RUST 129 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//! Port of OutlineFunctions from TypeScript (`Optimization/OutlineFunctions.ts`).7//!8//! Extracts anonymous function expressions that do not close over any local9//! variables into top-level outlined functions. The original instruction is10//! replaced with a `LoadGlobal` referencing the outlined function's generated name.11//!12//! Conditional on `env.config.enable_function_outlining`.1314use rustc_hash::FxHashSet;1516use react_compiler_hir::environment::Environment;17use react_compiler_hir::{18    FunctionId, HirFunction, IdentifierId, InstructionValue, NonLocalBinding,19};20use react_compiler_ssa::enter_ssa::placeholder_function;2122/// Outline anonymous function expressions that have no captured context variables.23///24/// Ported from TS `outlineFunctions` in `Optimization/OutlineFunctions.ts`.25pub fn outline_functions(26    func: &mut HirFunction,27    env: &mut Environment,28    fbt_operands: &FxHashSet<IdentifierId>,29) {30    // Collect per-instruction actions to maintain depth-first name allocation order.31    // Each entry: (instr index, function_id to recurse into, should_outline)32    enum Action {33        /// Recurse into an inner function (FunctionExpression or ObjectMethod)34        Recurse(FunctionId),35        /// Recurse then outline a FunctionExpression36        RecurseAndOutline {37            instr_idx: usize,38            function_id: FunctionId,39        },40    }4142    let mut actions: Vec<Action> = Vec::new();4344    for block in func.body.blocks.values() {45        for &instr_id in &block.instructions {46            let instr = &func.instructions[instr_id.0 as usize];47            let lvalue_id = instr.lvalue.identifier;4849            match &instr.value {50                InstructionValue::FunctionExpression { lowered_func, .. } => {51                    let inner_func = &env.functions[lowered_func.func.0 as usize];5253                    // Check outlining conditions (TS only checks func.id === null, not name):54                    // 1. No captured context variables55                    // 2. Anonymous (no explicit id on the inner function)56                    // 3. Not an fbt operand57                    if inner_func.context.is_empty()58                        && inner_func.id.is_none()59                        && !fbt_operands.contains(&lvalue_id)60                    {61                        actions.push(Action::RecurseAndOutline {62                            instr_idx: instr_id.0 as usize,63                            function_id: lowered_func.func,64                        });65                    } else {66                        actions.push(Action::Recurse(lowered_func.func));67                    }68                }69                InstructionValue::ObjectMethod { lowered_func, .. } => {70                    // Recurse into object methods (but don't outline them)71                    actions.push(Action::Recurse(lowered_func.func));72                }73                _ => {}74            }75        }76    }7778    // Process actions sequentially: for each instruction, recurse first (depth-first),79    // then generate name and outline. This matches TS ordering where inner functions80    // get names allocated before outer ones.81    for action in actions {82        match action {83            Action::Recurse(function_id) => {84                let mut inner_func = std::mem::replace(85                    &mut env.functions[function_id.0 as usize],86                    placeholder_function(),87                );88                outline_functions(&mut inner_func, env, fbt_operands);89                env.functions[function_id.0 as usize] = inner_func;90            }91            Action::RecurseAndOutline {92                instr_idx,93                function_id,94            } => {95                // First recurse into the inner function (depth-first)96                let mut inner_func = std::mem::replace(97                    &mut env.functions[function_id.0 as usize],98                    placeholder_function(),99                );100                outline_functions(&mut inner_func, env, fbt_operands);101                env.functions[function_id.0 as usize] = inner_func;102103                // Then generate the name and outline (after recursion, matching TS order)104                let hint: Option<String> = env.functions[function_id.0 as usize]105                    .id106                    .clone()107                    .or_else(|| env.functions[function_id.0 as usize].name_hint.clone());108                let generated_name = env.generate_globally_unique_identifier_name(hint.as_deref());109110                // Set the id on the inner function111                env.functions[function_id.0 as usize].id = Some(generated_name.clone());112113                // Outline the function114                let outlined_func = env.functions[function_id.0 as usize].clone();115                env.outline_function(outlined_func, None);116117                // Replace the instruction value with LoadGlobal118                let loc = func.instructions[instr_idx].value.loc().cloned();119                func.instructions[instr_idx].value = InstructionValue::LoadGlobal {120                    binding: NonLocalBinding::Global {121                        name: generated_name,122                    },123                    loc,124                };125            }126        }127    }128}

Code quality findings 13

Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let instr = &func.instructions[instr_id.0 as usize];
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let inner_func = &env.functions[lowered_func.func.0 as usize];
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
&mut env.functions[function_id.0 as usize],
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
env.functions[function_id.0 as usize] = inner_func;
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
&mut env.functions[function_id.0 as usize],
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
env.functions[function_id.0 as usize] = inner_func;
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let hint: Option<String> = env.functions[function_id.0 as usize]
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
.or_else(|| env.functions[function_id.0 as usize].name_hint.clone());
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
env.functions[function_id.0 as usize].id = Some(generated_name.clone());
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let outlined_func = env.functions[function_id.0 as usize].clone();
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let loc = func.instructions[instr_idx].value.loc().cloned();
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
func.instructions[instr_idx].value = InstructionValue::LoadGlobal {
Performance Info: Calling .push() repeatedly inside a loop without prior capacity reservation can lead to multiple reallocations. Consider using `Vec::with_capacity(n)` or `vec.reserve(n)` if the approximate number of elements is known.
info performance push-without-reserve
actions.push(Action::Recurse(lowered_func.func));

Get this view in your editor

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