Skip to main content

react_compiler_optimization/
optimize_props_method_calls.rs

1// Copyright (c) Meta Platforms, Inc. and affiliates.
2//
3// This source code is licensed under the MIT license found in the
4// LICENSE file in the root directory of this source tree.
5
6//! Converts `MethodCall` instructions on props objects into `CallExpression`
7//! instructions.
8//!
9//! When the receiver of a method call is typed as the component's props object,
10//! we can safely convert the method call `props.foo(args)` into a direct call
11//! `foo(args)` using the property as the callee. This simplifies downstream
12//! analysis by removing the receiver dependency.
13//!
14//! Analogous to TS `Optimization/OptimizePropsMethodCalls.ts`.
15
16use react_compiler_hir::environment::Environment;
17use react_compiler_hir::{HirFunction, InstructionValue, is_props_type};
18
19pub fn optimize_props_method_calls(func: &mut HirFunction, env: &Environment) {
20    for (_block_id, block) in &func.body.blocks {
21        let instruction_ids: Vec<_> = block.instructions.clone();
22        for instr_id in instruction_ids {
23            let instr = &mut func.instructions[instr_id.0 as usize];
24            let should_replace = matches!(
25                &instr.value,
26                InstructionValue::MethodCall { receiver, .. }
27                    if {
28                        let identifier = &env.identifiers[receiver.identifier.0 as usize];
29                        let ty = &env.types[identifier.type_.0 as usize];
30                        is_props_type(ty)
31                    }
32            );
33            if should_replace {
34                // Take the old value out, replacing with a temporary.
35                // The if-let is guaranteed to match since we checked above.
36                let old =
37                    std::mem::replace(&mut instr.value, InstructionValue::Debugger { loc: None });
38                match old {
39                    InstructionValue::MethodCall {
40                        property,
41                        args,
42                        loc,
43                        ..
44                    } => {
45                        instr.value = InstructionValue::CallExpression {
46                            callee: property,
47                            args,
48                            loc,
49                        };
50                    }
51                    _ => unreachable!(),
52                }
53            }
54        }
55    }
56}