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//! Infers which `Place`s are reactive.7//!8//! Ported from TypeScript `src/Inference/InferReactivePlaces.ts`.9//!10//! A place is reactive if it derives from any source of reactivity:11//! 1. Props (component parameters may change between renders)12//! 2. Hooks (can access state or context)13//! 3. `use` operator (can access context)14//! 4. Mutation with reactive operands15//! 5. Conditional assignment based on reactive control flow1617use rustc_hash::{FxHashMap, FxHashSet};1819use react_compiler_diagnostics::{CompilerDiagnostic, ErrorCategory};20use react_compiler_hir::dominator::post_dominator_frontier;21use react_compiler_hir::environment::Environment;22use react_compiler_hir::object_shape::HookKind;23use react_compiler_hir::visitors;24use react_compiler_hir::{25 BlockId, Effect, FunctionId, HirFunction, IdentifierId, InstructionValue, ParamPattern,26 Terminal, Type,27};2829use react_compiler_utils::DisjointSet;3031use crate::infer_reactive_scope_variables::find_disjoint_mutable_values;3233// =============================================================================34// Public API35// =============================================================================3637/// Infer which places in a function are reactive.38///39/// Corresponds to TS `inferReactivePlaces(fn: HIRFunction): void`.40pub fn infer_reactive_places(41 func: &mut HirFunction,42 env: &mut Environment,43) -> Result<(), CompilerDiagnostic> {44 let mut aliased_identifiers = find_disjoint_mutable_values(func, env);45 let mut reactive_map = ReactivityMap::new(&mut aliased_identifiers);46 let mut stable_sidemap = StableSidemap::new();4748 // Mark all function parameters as reactive49 for param in &func.params {50 let place = match param {51 ParamPattern::Place(p) => p,52 ParamPattern::Spread(s) => &s.place,53 };54 reactive_map.mark_reactive(place.identifier);55 }5657 // Compute control dominators58 let post_dominators = react_compiler_hir::dominator::compute_post_dominator_tree(59 func,60 env.next_block_id().0,61 false,62 )?;6364 // Collect block IDs for iteration65 let block_ids: Vec<BlockId> = func.body.blocks.keys().copied().collect();6667 // Track phi operand reactive flags during fixpoint.68 // In TS, isReactive() sets place.reactive as a side effect. But when a phi69 // is already reactive, the TS `continue`s and skips operand processing.70 // We track which phi operand Places should be marked reactive.71 // Key: (block_id, phi_idx, operand_idx), Value: should be reactive72 let mut phi_operand_reactive: FxHashMap<(BlockId, usize, usize), bool> = FxHashMap::default();7374 // Fixpoint iteration — compute reactive set75 loop {76 for block_id in &block_ids {77 let block = func.body.blocks.get(block_id).unwrap();78 let has_reactive_control =79 is_reactive_controlled_block(block.id, func, &post_dominators, &mut reactive_map);8081 // Process phi nodes82 let block = func.body.blocks.get(block_id).unwrap();83 for (phi_idx, phi) in block.phis.iter().enumerate() {84 if reactive_map.is_reactive(phi.place.identifier) {85 // TS does `continue` here — skips operand isReactive calls.86 // phi operand reactive flags stay as they were from last visit.87 continue;88 }89 let mut is_phi_reactive = false;90 for (op_idx, (_pred, operand)) in phi.operands.iter().enumerate() {91 let op_reactive = reactive_map.is_reactive(operand.identifier);92 // Record the reactive state for this operand at this point93 phi_operand_reactive.insert((*block_id, phi_idx, op_idx), op_reactive);94 if op_reactive {95 is_phi_reactive = true;96 break; // TS breaks here — remaining operands NOT visited97 }98 }99 if is_phi_reactive {100 reactive_map.mark_reactive(phi.place.identifier);101 } else {102 for (pred, _operand) in &phi.operands {103 if is_reactive_controlled_block(104 *pred,105 func,106 &post_dominators,107 &mut reactive_map,108 ) {109 reactive_map.mark_reactive(phi.place.identifier);110 break;111 }112 }113 }114 }115116 // Process instructions117 let block = func.body.blocks.get(block_id).unwrap();118 for instr_id in &block.instructions {119 let instr = &func.instructions[instr_id.0 as usize];120121 // Handle stable identifier sources122 stable_sidemap.handle_instruction(instr, env);123124 let value = &instr.value;125126 // Check if any operand is reactive127 let mut has_reactive_input = false;128 let operands: Vec<IdentifierId> =129 visitors::each_instruction_value_operand(value, env)130 .into_iter()131 .map(|p| p.identifier)132 .collect();133 for &op_id in &operands {134 let reactive = reactive_map.is_reactive(op_id);135 has_reactive_input = has_reactive_input || reactive;136 }137138 // Hooks and `use` operator are sources of reactivity139 match value {140 InstructionValue::CallExpression { callee, .. } => {141 let callee_ty = &env.types142 [env.identifiers[callee.identifier.0 as usize].type_.0 as usize];143 if get_hook_kind_for_type(env, callee_ty)?.is_some()144 || is_use_operator_type(callee_ty)145 {146 has_reactive_input = true;147 }148 }149 InstructionValue::MethodCall { property, .. } => {150 let property_ty = &env.types151 [env.identifiers[property.identifier.0 as usize].type_.0 as usize];152 if get_hook_kind_for_type(env, property_ty)?.is_some()153 || is_use_operator_type(property_ty)154 {155 has_reactive_input = true;156 }157 }158 _ => {}159 }160161 if has_reactive_input {162 // Mark lvalues reactive (unless stable)163 let lvalue_ids: Vec<IdentifierId> = visitors::each_instruction_lvalue(instr)164 .into_iter()165 .map(|p| p.identifier)166 .collect();167 for lvalue_id in lvalue_ids {168 if stable_sidemap.is_stable(lvalue_id) {169 continue;170 }171 reactive_map.mark_reactive(lvalue_id);172 }173 }174175 if has_reactive_input || has_reactive_control {176 // Mark mutable operands reactive177 let operand_places = visitors::each_instruction_value_operand(value, env);178 for op_place in &operand_places {179 match op_place.effect {180 Effect::Capture181 | Effect::Store182 | Effect::ConditionallyMutate183 | Effect::ConditionallyMutateIterator184 | Effect::Mutate => {185 let op_range =186 &env.identifiers[op_place.identifier.0 as usize].mutable_range;187 if op_range.contains(instr.id) {188 reactive_map.mark_reactive(op_place.identifier);189 }190 }191 Effect::Freeze | Effect::Read => {192 // no-op193 }194 Effect::Unknown => {195 return Err(CompilerDiagnostic::new(196 ErrorCategory::Invariant,197 &format!("Unexpected unknown effect at {:?}", op_place.loc),198 None,199 ));200 }201 }202 }203 }204 }205206 // Process terminal operands (just to mark them reactive for output)207 for op in visitors::each_terminal_operand(&block.terminal) {208 reactive_map.is_reactive(op.identifier);209 }210 }211212 if !reactive_map.snapshot() {213 break;214 }215 }216217 // Propagate reactivity to inner functions (read-only phase, just queries reactive_map)218 propagate_reactivity_to_inner_functions_outer(func, env, &mut reactive_map);219220 // Now apply reactive flags by replaying the traversal pattern.221 apply_reactive_flags_replay(222 func,223 env,224 &mut reactive_map,225 &mut stable_sidemap,226 &phi_operand_reactive,227 );228229 Ok(())230}231232// =============================================================================233// ReactivityMap234// =============================================================================235236struct ReactivityMap<'a> {237 has_changes: bool,238 reactive: FxHashSet<IdentifierId>,239 aliased_identifiers: &'a mut DisjointSet<IdentifierId>,240}241242impl<'a> ReactivityMap<'a> {243 fn new(aliased_identifiers: &'a mut DisjointSet<IdentifierId>) -> Self {244 ReactivityMap {245 has_changes: false,246 reactive: FxHashSet::default(),247 aliased_identifiers,248 }249 }250251 fn is_reactive(&mut self, id: IdentifierId) -> bool {252 let canonical = self.aliased_identifiers.find_opt(id).unwrap_or(id);253 self.reactive.contains(&canonical)254 }255256 fn mark_reactive(&mut self, id: IdentifierId) {257 let canonical = self.aliased_identifiers.find_opt(id).unwrap_or(id);258 if self.reactive.insert(canonical) {259 self.has_changes = true;260 }261 }262263 /// Reset change tracking, returns true if there were changes.264 fn snapshot(&mut self) -> bool {265 let had_changes = self.has_changes;266 self.has_changes = false;267 had_changes268 }269}270271// =============================================================================272// StableSidemap273// =============================================================================274275struct StableSidemap {276 map: FxHashMap<IdentifierId, bool>,277}278279impl StableSidemap {280 fn new() -> Self {281 StableSidemap {282 map: FxHashMap::default(),283 }284 }285286 fn handle_instruction(&mut self, instr: &react_compiler_hir::Instruction, env: &Environment) {287 let lvalue_id = instr.lvalue.identifier;288 let value = &instr.value;289290 match value {291 InstructionValue::CallExpression { callee, .. } => {292 let callee_ty =293 &env.types[env.identifiers[callee.identifier.0 as usize].type_.0 as usize];294 if evaluates_to_stable_type_or_container(env, callee_ty) {295 let lvalue_ty =296 &env.types[env.identifiers[lvalue_id.0 as usize].type_.0 as usize];297 if is_stable_type(lvalue_ty) {298 self.map.insert(lvalue_id, true);299 } else {300 self.map.insert(lvalue_id, false);301 }302 }303 }304 InstructionValue::MethodCall { property, .. } => {305 let property_ty =306 &env.types[env.identifiers[property.identifier.0 as usize].type_.0 as usize];307 if evaluates_to_stable_type_or_container(env, property_ty) {308 let lvalue_ty =309 &env.types[env.identifiers[lvalue_id.0 as usize].type_.0 as usize];310 if is_stable_type(lvalue_ty) {311 self.map.insert(lvalue_id, true);312 } else {313 self.map.insert(lvalue_id, false);314 }315 }316 }317 InstructionValue::PropertyLoad { object, .. } => {318 let source_id = object.identifier;319 if self.map.contains_key(&source_id) {320 let lvalue_ty =321 &env.types[env.identifiers[lvalue_id.0 as usize].type_.0 as usize];322 if is_stable_type_container(lvalue_ty) {323 self.map.insert(lvalue_id, false);324 } else if is_stable_type(lvalue_ty) {325 self.map.insert(lvalue_id, true);326 }327 }328 }329 InstructionValue::Destructure { value: val, .. } => {330 let source_id = val.identifier;331 if self.map.contains_key(&source_id) {332 let lvalue_ids: Vec<IdentifierId> = visitors::each_instruction_lvalue(instr)333 .into_iter()334 .map(|p| p.identifier)335 .collect();336 for lid in lvalue_ids {337 let lid_ty = &env.types[env.identifiers[lid.0 as usize].type_.0 as usize];338 if is_stable_type_container(lid_ty) {339 self.map.insert(lid, false);340 } else if is_stable_type(lid_ty) {341 self.map.insert(lid, true);342 }343 }344 }345 }346 InstructionValue::StoreLocal {347 lvalue, value: val, ..348 } => {349 if let Some(&entry) = self.map.get(&val.identifier) {350 self.map.insert(lvalue_id, entry);351 self.map.insert(lvalue.place.identifier, entry);352 }353 }354 InstructionValue::LoadLocal { place, .. } => {355 if let Some(&entry) = self.map.get(&place.identifier) {356 self.map.insert(lvalue_id, entry);357 }358 }359 _ => {}360 }361 }362363 fn is_stable(&self, id: IdentifierId) -> bool {364 self.map.get(&id).copied().unwrap_or(false)365 }366}367368// =============================================================================369// Control dominators (ported from ControlDominators.ts)370// =============================================================================371372fn is_reactive_controlled_block(373 block_id: BlockId,374 func: &HirFunction,375 post_dominators: &react_compiler_hir::dominator::PostDominator,376 reactive_map: &mut ReactivityMap,377) -> bool {378 let frontier = post_dominator_frontier(func, post_dominators, block_id);379 for frontier_block_id in &frontier {380 let control_block = func.body.blocks.get(frontier_block_id).unwrap();381 match &control_block.terminal {382 Terminal::If { test, .. } | Terminal::Branch { test, .. } => {383 if reactive_map.is_reactive(test.identifier) {384 return true;385 }386 }387 Terminal::Switch { test, cases, .. } => {388 if reactive_map.is_reactive(test.identifier) {389 return true;390 }391 for case in cases {392 if let Some(ref case_test) = case.test {393 if reactive_map.is_reactive(case_test.identifier) {394 return true;395 }396 }397 }398 }399 _ => {}400 }401 }402 false403}404405// =============================================================================406// Type helpers (ported from HIR.ts)407// =============================================================================408409use react_compiler_hir::is_use_operator_type;410411fn get_hook_kind_for_type<'a>(412 env: &'a Environment,413 ty: &Type,414) -> Result<Option<&'a HookKind>, CompilerDiagnostic> {415 env.get_hook_kind_for_type(ty)416}417418fn is_stable_type(ty: &Type) -> bool {419 match ty {420 Type::Function {421 shape_id: Some(id), ..422 } => {423 matches!(424 id.as_str(),425 "BuiltInSetState"426 | "BuiltInSetActionState"427 | "BuiltInDispatch"428 | "BuiltInStartTransition"429 | "BuiltInSetOptimistic"430 )431 }432 Type::Object { shape_id: Some(id) } => {433 matches!(id.as_str(), "BuiltInUseRefId")434 }435 _ => false,436 }437}438439fn is_stable_type_container(ty: &Type) -> bool {440 match ty {441 Type::Object { shape_id: Some(id) } => {442 matches!(443 id.as_str(),444 "BuiltInUseState"445 | "BuiltInUseActionState"446 | "BuiltInUseReducer"447 | "BuiltInUseOptimistic"448 | "BuiltInUseTransition"449 )450 }451 _ => false,452 }453}454455fn evaluates_to_stable_type_or_container(env: &Environment, callee_ty: &Type) -> bool {456 if let Some(hook_kind) = get_hook_kind_for_type(env, callee_ty).ok().flatten() {457 matches!(458 hook_kind,459 HookKind::UseState460 | HookKind::UseReducer461 | HookKind::UseActionState462 | HookKind::UseRef463 | HookKind::UseTransition464 | HookKind::UseOptimistic465 )466 } else {467 false468 }469}470471// =============================================================================472// Propagate reactivity to inner functions473// =============================================================================474475fn propagate_reactivity_to_inner_functions_outer(476 func: &HirFunction,477 env: &Environment,478 reactive_map: &mut ReactivityMap,479) {480 for (_block_id, block) in &func.body.blocks {481 for instr_id in &block.instructions {482 let instr = &func.instructions[instr_id.0 as usize];483 match &instr.value {484 InstructionValue::FunctionExpression { lowered_func, .. }485 | InstructionValue::ObjectMethod { lowered_func, .. } => {486 propagate_reactivity_to_inner_functions_inner(487 lowered_func.func,488 env,489 reactive_map,490 );491 }492 _ => {}493 }494 }495 }496}497498fn propagate_reactivity_to_inner_functions_inner(499 func_id: FunctionId,500 env: &Environment,501 reactive_map: &mut ReactivityMap,502) {503 let inner_func = &env.functions[func_id.0 as usize];504505 for (_block_id, block) in &inner_func.body.blocks {506 for instr_id in &block.instructions {507 let instr = &inner_func.instructions[instr_id.0 as usize];508509 for op in visitors::each_instruction_value_operand(&instr.value, env) {510 reactive_map.is_reactive(op.identifier);511 }512513 match &instr.value {514 InstructionValue::FunctionExpression { lowered_func, .. }515 | InstructionValue::ObjectMethod { lowered_func, .. } => {516 propagate_reactivity_to_inner_functions_inner(517 lowered_func.func,518 env,519 reactive_map,520 );521 }522 _ => {}523 }524 }525526 for op in visitors::each_terminal_operand(&block.terminal) {527 reactive_map.is_reactive(op.identifier);528 }529 }530}531532// =============================================================================533// Apply reactive flags to the HIR (replay pass)534// =============================================================================535536fn apply_reactive_flags_replay(537 func: &mut HirFunction,538 env: &mut Environment,539 reactive_map: &mut ReactivityMap,540 stable_sidemap: &mut StableSidemap,541 phi_operand_reactive: &FxHashMap<(BlockId, usize, usize), bool>,542) {543 let reactive_ids = build_reactive_id_set(reactive_map);544545 // 1. Mark params546 for param in &mut func.params {547 let place = match param {548 ParamPattern::Place(p) => p,549 ParamPattern::Spread(s) => &mut s.place,550 };551 place.reactive = true;552 }553554 // 2. Walk blocks555 let block_ids: Vec<BlockId> = func.body.blocks.keys().copied().collect();556557 for block_id in &block_ids {558 let block = func.body.blocks.get(block_id).unwrap();559560 // 2a. Phi nodes561 let phi_count = block.phis.len();562 for phi_idx in 0..phi_count {563 let block = func.body.blocks.get_mut(block_id).unwrap();564 let phi = &mut block.phis[phi_idx];565566 if reactive_ids.contains(&phi.place.identifier) {567 phi.place.reactive = true;568 }569570 for (op_idx, (_pred, operand)) in phi.operands.iter_mut().enumerate() {571 if let Some(&is_reactive) = phi_operand_reactive.get(&(*block_id, phi_idx, op_idx))572 {573 if is_reactive {574 operand.reactive = true;575 }576 }577 }578 }579580 // 2b. Instructions581 let block = func.body.blocks.get(block_id).unwrap();582 let instr_ids: Vec<react_compiler_hir::InstructionId> = block.instructions.clone();583584 for instr_id in &instr_ids {585 let instr = &func.instructions[instr_id.0 as usize];586587 // Compute hasReactiveInput by checking value operands588 let value_operand_ids: Vec<IdentifierId> =589 visitors::each_instruction_value_operand(&instr.value, env)590 .into_iter()591 .map(|p| p.identifier)592 .collect();593 let mut has_reactive_input = false;594 for &op_id in &value_operand_ids {595 if reactive_ids.contains(&op_id) {596 has_reactive_input = true;597 }598 }599600 // Check hooks/use601 match &instr.value {602 InstructionValue::CallExpression { callee, .. } => {603 let callee_ty =604 &env.types[env.identifiers[callee.identifier.0 as usize].type_.0 as usize];605 if get_hook_kind_for_type(env, callee_ty)606 .ok()607 .flatten()608 .is_some()609 || is_use_operator_type(callee_ty)610 {611 has_reactive_input = true;612 }613 }614 InstructionValue::MethodCall { property, .. } => {615 let property_ty = &env.types616 [env.identifiers[property.identifier.0 as usize].type_.0 as usize];617 if get_hook_kind_for_type(env, property_ty)618 .ok()619 .flatten()620 .is_some()621 || is_use_operator_type(property_ty)622 {623 has_reactive_input = true;624 }625 }626 _ => {}627 }628629 // Value operands: set reactive flag using canonical visitor630 let instr = &mut func.instructions[instr_id.0 as usize];631 visitors::for_each_instruction_value_operand_mut(&mut instr.value, &mut |place| {632 if reactive_ids.contains(&place.identifier) {633 place.reactive = true;634 }635 });636 // FunctionExpression/ObjectMethod context variables require env access637 if let InstructionValue::FunctionExpression { lowered_func, .. }638 | InstructionValue::ObjectMethod { lowered_func, .. } = &mut instr.value639 {640 let inner_func = &mut env.functions[lowered_func.func.0 as usize];641 for ctx in &mut inner_func.context {642 if reactive_ids.contains(&ctx.identifier) {643 ctx.reactive = true;644 }645 }646 }647648 // Lvalues: markReactive is called only when hasReactiveInput649 if has_reactive_input {650 let lvalue_id = instr.lvalue.identifier;651 if !stable_sidemap.is_stable(lvalue_id) && reactive_ids.contains(&lvalue_id) {652 instr.lvalue.reactive = true;653 }654 // Handle value lvalues — includes DeclareContext/StoreContext which655 // for_each_instruction_lvalue_mut skips, so we use a direct match.656 match &mut instr.value {657 InstructionValue::DeclareLocal { lvalue, .. }658 | InstructionValue::DeclareContext { lvalue, .. }659 | InstructionValue::StoreLocal { lvalue, .. }660 | InstructionValue::StoreContext { lvalue, .. } => {661 let id = lvalue.place.identifier;662 if !stable_sidemap.is_stable(id) && reactive_ids.contains(&id) {663 lvalue.place.reactive = true;664 }665 }666 InstructionValue::Destructure { lvalue, .. } => {667 visitors::for_each_pattern_operand_mut(&mut lvalue.pattern, &mut |place| {668 if !stable_sidemap.is_stable(place.identifier)669 && reactive_ids.contains(&place.identifier)670 {671 place.reactive = true;672 }673 });674 }675 InstructionValue::PrefixUpdate { lvalue, .. }676 | InstructionValue::PostfixUpdate { lvalue, .. } => {677 let id = lvalue.identifier;678 if !stable_sidemap.is_stable(id) && reactive_ids.contains(&id) {679 lvalue.reactive = true;680 }681 }682 _ => {}683 }684 }685 }686687 // 2c. Terminal operands688 let block = func.body.blocks.get_mut(block_id).unwrap();689 visitors::for_each_terminal_operand_mut(&mut block.terminal, &mut |place| {690 if reactive_ids.contains(&place.identifier) {691 place.reactive = true;692 }693 });694 }695696 // 3. Apply to inner functions697 apply_reactive_flags_to_inner_functions(func, env, &reactive_ids);698}699700fn build_reactive_id_set(reactive_map: &mut ReactivityMap) -> FxHashSet<IdentifierId> {701 let mut result = FxHashSet::default();702 for &id in &reactive_map.reactive {703 result.insert(id);704 }705 let reactive = &reactive_map.reactive;706 reactive_map.aliased_identifiers.for_each(|id, canonical| {707 if reactive.contains(&canonical) {708 result.insert(id);709 }710 });711 result712}713714fn apply_reactive_flags_to_inner_functions(715 func: &HirFunction,716 env: &mut Environment,717 reactive_ids: &FxHashSet<IdentifierId>,718) {719 for (_block_id, block) in &func.body.blocks {720 for instr_id in &block.instructions {721 let instr = &func.instructions[instr_id.0 as usize];722 match &instr.value {723 InstructionValue::FunctionExpression { lowered_func, .. }724 | InstructionValue::ObjectMethod { lowered_func, .. } => {725 apply_reactive_flags_to_inner_func(lowered_func.func, env, reactive_ids);726 }727 _ => {}728 }729 }730 }731}732733fn apply_reactive_flags_to_inner_func(734 func_id: FunctionId,735 env: &mut Environment,736 reactive_ids: &FxHashSet<IdentifierId>,737) {738 // Collect nested function IDs first to avoid borrow issues739 let nested_func_ids: Vec<FunctionId> = {740 let func = &env.functions[func_id.0 as usize];741 let mut ids = Vec::new();742 for (_block_id, block) in &func.body.blocks {743 for instr_id in &block.instructions {744 let instr = &func.instructions[instr_id.0 as usize];745 match &instr.value {746 InstructionValue::FunctionExpression { lowered_func, .. }747 | InstructionValue::ObjectMethod { lowered_func, .. } => {748 ids.push(lowered_func.func);749 }750 _ => {}751 }752 }753 }754 ids755 };756757 // Apply reactive flags using canonical visitors758 let inner_func = &mut env.functions[func_id.0 as usize];759 for (_block_id, block) in &mut inner_func.body.blocks {760 for instr_id in &block.instructions {761 let instr = &mut inner_func.instructions[instr_id.0 as usize];762 visitors::for_each_instruction_value_operand_mut(&mut instr.value, &mut |place| {763 if reactive_ids.contains(&place.identifier) {764 place.reactive = true;765 }766 });767 }768 visitors::for_each_terminal_operand_mut(&mut block.terminal, &mut |place| {769 if reactive_ids.contains(&place.identifier) {770 place.reactive = true;771 }772 });773 }774775 // Recurse into nested functions, and set reactive on their context variables776 for nested_id in nested_func_ids {777 let nested_func = &mut env.functions[nested_id.0 as usize];778 for ctx in &mut nested_func.context {779 if reactive_ids.contains(&ctx.identifier) {780 ctx.reactive = true;781 }782 }783 apply_reactive_flags_to_inner_func(nested_id, env, reactive_ids);784 }785}
Code quality findings 39
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning
correctness
unwrap-usage
let block = func.body.blocks.get(block_id).unwrap();
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning
correctness
unwrap-usage
let block = func.body.blocks.get(block_id).unwrap();
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning
correctness
unwrap-usage
let block = func.body.blocks.get(block_id).unwrap();
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
[env.identifiers[callee.identifier.0 as usize].type_.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.identifiers[property.identifier.0 as usize].type_.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.identifiers[op_place.identifier.0 as usize].mutable_range;
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.types[env.identifiers[callee.identifier.0 as usize].type_.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.types[env.identifiers[lvalue_id.0 as usize].type_.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.types[env.identifiers[property.identifier.0 as usize].type_.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.types[env.identifiers[lvalue_id.0 as usize].type_.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.types[env.identifiers[lvalue_id.0 as usize].type_.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 lid_ty = &env.types[env.identifiers[lid.0 as usize].type_.0 as usize];
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning
correctness
unwrap-usage
let control_block = func.body.blocks.get(frontier_block_id).unwrap();
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[func_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 instr = &inner_func.instructions[instr_id.0 as usize];
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning
correctness
unwrap-usage
let block = func.body.blocks.get(block_id).unwrap();
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning
correctness
unwrap-usage
let block = func.body.blocks.get_mut(block_id).unwrap();
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 phi = &mut block.phis[phi_idx];
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning
correctness
unwrap-usage
let block = func.body.blocks.get(block_id).unwrap();
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
&env.types[env.identifiers[callee.identifier.0 as usize].type_.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.identifiers[property.identifier.0 as usize].type_.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 instr = &mut 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 = &mut env.functions[lowered_func.func.0 as usize];
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning
correctness
unwrap-usage
let block = func.body.blocks.get_mut(block_id).unwrap();
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 func = &env.functions[func_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 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 = &mut env.functions[func_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 instr = &mut inner_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 nested_func = &mut env.functions[nested_id.0 as usize];
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match &instr.value {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match &instr.value {
Performance Info: Frequent cloning, especially of Strings, Vecs, or other heap-allocated types inside loops, can be expensive. Consider using references/borrowing where possible.
info
performance
clone-in-loop
let instr_ids: Vec<react_compiler_hir::InstructionId> = block.instructions.clone();
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match &instr.value {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match &instr.value {
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
ids.push(lowered_func.func);