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::{is_props_type, HirFunction, InstructionValue};
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 = std::mem::replace(
37 &mut instr.value,
38 InstructionValue::Debugger { loc: None },
39 );
40 match old {
41 InstructionValue::MethodCall {
42 property,
43 args,
44 loc,
45 ..
46 } => {
47 instr.value = InstructionValue::CallExpression {
48 callee: property,
49 args,
50 loc,
51 };
52 }
53 _ => unreachable!(),
54 }
55 }
56 }
57 }
58}