| 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 | |
| 16 | use react_compiler_hir::environment::Environment; |
| 17 | use react_compiler_hir::{HirFunction, InstructionValue, is_props_type}; |
| 18 | |
| 19 | pub 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 | } |