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 mutable ranges for identifiers and populates Place effects.7//!8//! Ported from TypeScript `src/Inference/InferMutationAliasingRanges.ts`.9//!10//! This pass builds an abstract model of the heap and interprets the effects of11//! the given function in order to determine:12//! - The mutable ranges of all identifiers in the function13//! - The externally-visible effects of the function (mutations of params/context14//! vars, aliasing between params/context-vars/return-value)15//! - The legacy `Effect` to store on each Place1617use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};1819use indexmap::IndexMap;2021use react_compiler_diagnostics::{CompilerDiagnostic, ErrorCategory};22use react_compiler_hir::environment::Environment;23use react_compiler_hir::type_config::{ValueKind, ValueReason};24use react_compiler_hir::visitors::{25 each_instruction_value_lvalue, for_each_instruction_value_lvalue_mut,26 for_each_instruction_value_operand_mut, for_each_terminal_operand_mut,27};28use react_compiler_hir::{29 AliasingEffect, BlockId, Effect, EvaluationOrder, FunctionId, HirFunction, IdentifierId,30 InstructionValue, MutationReason, Place, SourceLocation, is_jsx_type, is_primitive_type,31};3233// =============================================================================34// MutationKind35// =============================================================================3637#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]38#[allow(dead_code)]39enum MutationKind {40 None = 0,41 Conditional = 1,42 Definite = 2,43}4445// =============================================================================46// Node and AliasingState47// =============================================================================4849#[derive(Debug, Clone, Copy, PartialEq, Eq)]50enum EdgeKind {51 Capture,52 Alias,53 MaybeAlias,54}5556#[derive(Debug, Clone)]57struct Edge {58 index: usize,59 node: IdentifierId,60 kind: EdgeKind,61}6263#[derive(Debug, Clone)]64struct MutationInfo {65 kind: MutationKind,66 loc: Option<SourceLocation>,67}6869#[derive(Debug, Clone)]70enum NodeValue {71 Object,72 Phi,73 Function { function_id: FunctionId },74}7576#[derive(Debug, Clone)]77struct Node {78 id: IdentifierId,79 created_from: IndexMap<IdentifierId, usize, FxBuildHasher>,80 captures: IndexMap<IdentifierId, usize, FxBuildHasher>,81 aliases: IndexMap<IdentifierId, usize, FxBuildHasher>,82 maybe_aliases: IndexMap<IdentifierId, usize, FxBuildHasher>,83 edges: Vec<Edge>,84 transitive: Option<MutationInfo>,85 local: Option<MutationInfo>,86 last_mutated: usize,87 mutation_reason: Option<MutationReason>,88 value: NodeValue,89}9091impl Node {92 fn new(id: IdentifierId, value: NodeValue) -> Self {93 Node {94 id,95 created_from: IndexMap::default(),96 captures: IndexMap::default(),97 aliases: IndexMap::default(),98 maybe_aliases: IndexMap::default(),99 edges: Vec::new(),100 transitive: None,101 local: None,102 last_mutated: 0,103 mutation_reason: None,104 value,105 }106 }107}108109struct AliasingState {110 nodes: IndexMap<IdentifierId, Node, FxBuildHasher>,111}112113impl AliasingState {114 fn new() -> Self {115 AliasingState {116 nodes: IndexMap::default(),117 }118 }119120 fn create(&mut self, place: &Place, value: NodeValue) {121 self.nodes122 .insert(place.identifier, Node::new(place.identifier, value));123 }124125 fn create_from(&mut self, index: usize, from: &Place, into: &Place) {126 self.create(into, NodeValue::Object);127 let from_id = from.identifier;128 let into_id = into.identifier;129 // Add forward edge from -> into on the from node130 if let Some(from_node) = self.nodes.get_mut(&from_id) {131 from_node.edges.push(Edge {132 index,133 node: into_id,134 kind: EdgeKind::Alias,135 });136 }137 // Add created_from on the into node138 if let Some(to_node) = self.nodes.get_mut(&into_id) {139 to_node.created_from.entry(from_id).or_insert(index);140 }141 }142143 fn capture(&mut self, index: usize, from: &Place, into: &Place) {144 let from_id = from.identifier;145 let into_id = into.identifier;146 if !self.nodes.contains_key(&from_id) || !self.nodes.contains_key(&into_id) {147 return;148 }149 self.nodes.get_mut(&from_id).unwrap().edges.push(Edge {150 index,151 node: into_id,152 kind: EdgeKind::Capture,153 });154 self.nodes155 .get_mut(&into_id)156 .unwrap()157 .captures158 .entry(from_id)159 .or_insert(index);160 }161162 fn assign(&mut self, index: usize, from: &Place, into: &Place) {163 let from_id = from.identifier;164 let into_id = into.identifier;165 if !self.nodes.contains_key(&from_id) || !self.nodes.contains_key(&into_id) {166 return;167 }168 self.nodes.get_mut(&from_id).unwrap().edges.push(Edge {169 index,170 node: into_id,171 kind: EdgeKind::Alias,172 });173 self.nodes174 .get_mut(&into_id)175 .unwrap()176 .aliases177 .entry(from_id)178 .or_insert(index);179 }180181 fn maybe_alias(&mut self, index: usize, from: &Place, into: &Place) {182 let from_id = from.identifier;183 let into_id = into.identifier;184 if !self.nodes.contains_key(&from_id) || !self.nodes.contains_key(&into_id) {185 return;186 }187 self.nodes.get_mut(&from_id).unwrap().edges.push(Edge {188 index,189 node: into_id,190 kind: EdgeKind::MaybeAlias,191 });192 self.nodes193 .get_mut(&into_id)194 .unwrap()195 .maybe_aliases196 .entry(from_id)197 .or_insert(index);198 }199200 fn render(&self, index: usize, start: IdentifierId, env: &mut Environment) {201 let mut seen = FxHashSet::default();202 let mut queue: Vec<IdentifierId> = vec![start];203 while let Some(current) = queue.pop() {204 if !seen.insert(current) {205 continue;206 }207 let node = match self.nodes.get(¤t) {208 Some(n) => n,209 None => continue,210 };211 if node.transitive.is_some() || node.local.is_some() {212 continue;213 }214 if let NodeValue::Function { function_id } = &node.value {215 append_function_errors(env, *function_id);216 }217 for (&alias, &when) in &node.created_from {218 if when >= index {219 continue;220 }221 queue.push(alias);222 }223 for (&alias, &when) in &node.aliases {224 if when >= index {225 continue;226 }227 queue.push(alias);228 }229 for (&capture, &when) in &node.captures {230 if when >= index {231 continue;232 }233 queue.push(capture);234 }235 }236 }237238 fn mutate(239 &mut self,240 index: usize,241 start: IdentifierId,242 end: Option<EvaluationOrder>, // None for simulated mutations243 transitive: bool,244 start_kind: MutationKind,245 loc: Option<SourceLocation>,246 reason: Option<MutationReason>,247 env: &mut Environment,248 should_record_errors: bool,249 ) {250 #[derive(Clone)]251 struct QueueEntry {252 place: IdentifierId,253 transitive: bool,254 direction: Direction,255 kind: MutationKind,256 }257 #[derive(Clone, Copy, PartialEq)]258 enum Direction {259 Backwards,260 Forwards,261 }262263 let mut seen: FxHashMap<IdentifierId, MutationKind> = FxHashMap::default();264 let mut queue: Vec<QueueEntry> = vec![QueueEntry {265 place: start,266 transitive,267 direction: Direction::Backwards,268 kind: start_kind,269 }];270271 while let Some(entry) = queue.pop() {272 let current = entry.place;273 let previous_kind = seen.get(¤t).copied();274 if let Some(prev) = previous_kind {275 if prev >= entry.kind {276 continue;277 }278 }279 seen.insert(current, entry.kind);280281 let node = match self.nodes.get_mut(¤t) {282 Some(n) => n,283 None => continue,284 };285286 if node.mutation_reason.is_none() {287 node.mutation_reason = reason.clone();288 }289 node.last_mutated = node.last_mutated.max(index);290291 if let Some(end_val) = end {292 let ident = &mut env.identifiers[node.id.0 as usize];293 ident.mutable_range.end = EvaluationOrder(ident.mutable_range.end.0.max(end_val.0));294 }295296 if let NodeValue::Function { function_id } = &node.value {297 if node.transitive.is_none() && node.local.is_none() {298 if should_record_errors {299 append_function_errors(env, *function_id);300 }301 }302 }303304 if entry.transitive {305 match &node.transitive {306 None => {307 node.transitive = Some(MutationInfo {308 kind: entry.kind,309 loc,310 });311 }312 Some(existing) if existing.kind < entry.kind => {313 node.transitive = Some(MutationInfo {314 kind: entry.kind,315 loc,316 });317 }318 _ => {}319 }320 } else {321 match &node.local {322 None => {323 node.local = Some(MutationInfo {324 kind: entry.kind,325 loc,326 });327 }328 Some(existing) if existing.kind < entry.kind => {329 node.local = Some(MutationInfo {330 kind: entry.kind,331 loc,332 });333 }334 _ => {}335 }336 }337338 // Forward edges: Capture a -> b, Alias a -> b: mutate(a) => mutate(b)339 // Collect edges to avoid borrow conflict340 let edges: Vec<Edge> = node.edges.clone();341 let node_value_kind = match &node.value {342 NodeValue::Phi => "Phi",343 _ => "Other",344 };345 let node_aliases: Vec<(IdentifierId, usize)> =346 node.aliases.iter().map(|(&k, &v)| (k, v)).collect();347 let node_maybe_aliases: Vec<(IdentifierId, usize)> =348 node.maybe_aliases.iter().map(|(&k, &v)| (k, v)).collect();349 let node_captures: Vec<(IdentifierId, usize)> =350 node.captures.iter().map(|(&k, &v)| (k, v)).collect();351 let node_created_from: Vec<(IdentifierId, usize)> =352 node.created_from.iter().map(|(&k, &v)| (k, v)).collect();353354 for edge in &edges {355 if edge.index >= index {356 break;357 }358 queue.push(QueueEntry {359 place: edge.node,360 transitive: entry.transitive,361 direction: Direction::Forwards,362 // MaybeAlias edges downgrade to conditional mutation363 kind: if edge.kind == EdgeKind::MaybeAlias {364 MutationKind::Conditional365 } else {366 entry.kind367 },368 });369 }370371 for (alias, when) in &node_created_from {372 if *when >= index {373 continue;374 }375 queue.push(QueueEntry {376 place: *alias,377 transitive: true,378 direction: Direction::Backwards,379 kind: entry.kind,380 });381 }382383 if entry.direction == Direction::Backwards || node_value_kind != "Phi" {384 // Backward alias edges385 for (alias, when) in &node_aliases {386 if *when >= index {387 continue;388 }389 queue.push(QueueEntry {390 place: *alias,391 transitive: entry.transitive,392 direction: Direction::Backwards,393 kind: entry.kind,394 });395 }396 // MaybeAlias backward edges (downgrade to conditional)397 for (alias, when) in &node_maybe_aliases {398 if *when >= index {399 continue;400 }401 queue.push(QueueEntry {402 place: *alias,403 transitive: entry.transitive,404 direction: Direction::Backwards,405 kind: MutationKind::Conditional,406 });407 }408 }409410 // Only transitive mutations affect captures backward411 if entry.transitive {412 for (capture, when) in &node_captures {413 if *when >= index {414 continue;415 }416 queue.push(QueueEntry {417 place: *capture,418 transitive: entry.transitive,419 direction: Direction::Backwards,420 kind: entry.kind,421 });422 }423 }424 }425 }426}427428// =============================================================================429// Helper: append function errors430// =============================================================================431432fn append_function_errors(env: &mut Environment, function_id: FunctionId) {433 let func = &env.functions[function_id.0 as usize];434 if let Some(ref effects) = func.aliasing_effects {435 // Collect errors first to avoid borrow conflict436 let errors: Vec<_> = effects437 .iter()438 .filter_map(|effect| match effect {439 AliasingEffect::Impure { error, .. }440 | AliasingEffect::MutateFrozen { error, .. }441 | AliasingEffect::MutateGlobal { error, .. } => Some(error.clone()),442 _ => None,443 })444 .collect();445 for error in errors {446 env.record_diagnostic(error);447 }448 }449}450451// =============================================================================452// Public entry point453// =============================================================================454455/// Infers mutable ranges for identifiers and populates Place effects.456///457/// Returns the externally-visible effects of the function (mutations of458/// params/context-vars, aliasing between params/context-vars/return).459///460/// Corresponds to TS `inferMutationAliasingRanges(fn, {isFunctionExpression})`.461pub fn infer_mutation_aliasing_ranges(462 func: &mut HirFunction,463 env: &mut Environment,464 is_function_expression: bool,465) -> Result<Vec<AliasingEffect>, CompilerDiagnostic> {466 let mut function_effects: Vec<AliasingEffect> = Vec::new();467468 // =========================================================================469 // Part 1: Build data flow graph and infer mutable ranges470 // =========================================================================471 let mut state = AliasingState::new();472473 struct PendingPhiOperand {474 from: Place,475 into: Place,476 index: usize,477 }478 let mut pending_phis: FxHashMap<BlockId, Vec<PendingPhiOperand>> = FxHashMap::default();479480 struct PendingMutation {481 index: usize,482 id: EvaluationOrder,483 transitive: bool,484 kind: MutationKind,485 place: Place,486 reason: Option<MutationReason>,487 }488 let mut mutations: Vec<PendingMutation> = Vec::new();489490 struct PendingRender {491 index: usize,492 place: Place,493 }494 let mut renders: Vec<PendingRender> = Vec::new();495496 let mut index: usize = 0;497498 let should_record_errors = !is_function_expression && env.enable_validations();499500 // Create nodes for params, context vars, and return501 for param in &func.params {502 let place = match param {503 react_compiler_hir::ParamPattern::Place(p) => p,504 react_compiler_hir::ParamPattern::Spread(s) => &s.place,505 };506 state.create(place, NodeValue::Object);507 }508 for ctx in &func.context {509 state.create(ctx, NodeValue::Object);510 }511 state.create(&func.returns, NodeValue::Object);512513 let mut seen_blocks: FxHashSet<BlockId> = FxHashSet::default();514515 // Collect block iteration data to avoid borrow conflicts516 let block_order: Vec<BlockId> = func.body.blocks.keys().cloned().collect();517518 for &block_id in &block_order {519 let block = &func.body.blocks[&block_id];520521 // Process phis522 for phi in &block.phis {523 state.create(&phi.place, NodeValue::Phi);524 for (&pred, operand) in &phi.operands {525 if !seen_blocks.contains(&pred) {526 pending_phis527 .entry(pred)528 .or_insert_with(Vec::new)529 .push(PendingPhiOperand {530 from: operand.clone(),531 into: phi.place.clone(),532 index: index,533 });534 index += 1;535 } else {536 state.assign(index, operand, &phi.place);537 index += 1;538 }539 }540 }541 seen_blocks.insert(block_id);542543 // Process instruction effects544 let instr_ids: Vec<_> = block.instructions.clone();545 for instr_id in &instr_ids {546 let instr = &func.instructions[instr_id.0 as usize];547 let instr_eval_order = instr.id;548 let effects = match &instr.effects {549 Some(e) => e.clone(),550 None => continue,551 };552 for effect in &effects {553 match effect {554 AliasingEffect::Create { into, .. } => {555 state.create(into, NodeValue::Object);556 }557 AliasingEffect::CreateFunction {558 into, function_id, ..559 } => {560 state.create(561 into,562 NodeValue::Function {563 function_id: *function_id,564 },565 );566 }567 AliasingEffect::CreateFrom { from, into } => {568 state.create_from(index, from, into);569 index += 1;570 }571 AliasingEffect::Assign { from, into } => {572 if !state.nodes.contains_key(&into.identifier) {573 state.create(into, NodeValue::Object);574 }575 state.assign(index, from, into);576 index += 1;577 }578 AliasingEffect::Alias { from, into } => {579 state.assign(index, from, into);580 index += 1;581 }582 AliasingEffect::MaybeAlias { from, into } => {583 state.maybe_alias(index, from, into);584 index += 1;585 }586 AliasingEffect::Capture { from, into } => {587 state.capture(index, from, into);588 index += 1;589 }590 AliasingEffect::MutateTransitive { value }591 | AliasingEffect::MutateTransitiveConditionally { value } => {592 let is_transitive_conditional =593 matches!(effect, AliasingEffect::MutateTransitiveConditionally { .. });594 mutations.push(PendingMutation {595 index: index,596 id: instr_eval_order,597 transitive: true,598 kind: if is_transitive_conditional {599 MutationKind::Conditional600 } else {601 MutationKind::Definite602 },603 reason: None,604 place: value.clone(),605 });606 index += 1;607 }608 AliasingEffect::Mutate { value, reason } => {609 mutations.push(PendingMutation {610 index: index,611 id: instr_eval_order,612 transitive: false,613 kind: MutationKind::Definite,614 reason: reason.clone(),615 place: value.clone(),616 });617 index += 1;618 }619 AliasingEffect::MutateConditionally { value } => {620 mutations.push(PendingMutation {621 index: index,622 id: instr_eval_order,623 transitive: false,624 kind: MutationKind::Conditional,625 reason: None,626 place: value.clone(),627 });628 index += 1;629 }630 AliasingEffect::MutateFrozen { .. }631 | AliasingEffect::MutateGlobal { .. }632 | AliasingEffect::Impure { .. } => {633 if should_record_errors {634 match effect {635 AliasingEffect::MutateFrozen { error, .. }636 | AliasingEffect::MutateGlobal { error, .. }637 | AliasingEffect::Impure { error, .. } => {638 env.record_diagnostic(error.clone());639 }640 _ => unreachable!(),641 }642 }643 function_effects.push(effect.clone());644 }645 AliasingEffect::Render { place } => {646 renders.push(PendingRender {647 index: index,648 place: place.clone(),649 });650 index += 1;651 function_effects.push(effect.clone());652 }653 // Other effects (Freeze, ImmutableCapture, Apply) are no-ops here654 _ => {}655 }656 }657 }658659 // Process pending phis for this block660 let block = &func.body.blocks[&block_id];661 if let Some(block_phis) = pending_phis.remove(&block_id) {662 for pending in block_phis {663 state.assign(pending.index, &pending.from, &pending.into);664 }665 }666667 // Handle return terminal668 let terminal = &block.terminal;669 if let react_compiler_hir::Terminal::Return { value, .. } = terminal {670 state.assign(index, value, &func.returns);671 index += 1;672 }673674 // Handle terminal effects (MaybeThrow and Return)675 let terminal_effects = match terminal {676 react_compiler_hir::Terminal::MaybeThrow { effects, .. }677 | react_compiler_hir::Terminal::Return { effects, .. } => effects.clone(),678 _ => None,679 };680 if let Some(effects) = terminal_effects {681 for effect in &effects {682 match effect {683 AliasingEffect::Alias { from, into } => {684 state.assign(index, from, into);685 index += 1;686 }687 AliasingEffect::Freeze { .. } => {688 // Expected for MaybeThrow terminals, skip689 }690 _ => {691 // TS: CompilerError.invariant(effect.kind === 'Freeze', ...)692 // We skip non-Alias, non-Freeze effects693 }694 }695 }696 }697 }698699 // Process mutations700 for mutation in &mutations {701 state.mutate(702 mutation.index,703 mutation.place.identifier,704 Some(EvaluationOrder(mutation.id.0 + 1)),705 mutation.transitive,706 mutation.kind,707 mutation.place.loc,708 mutation.reason.clone(),709 env,710 should_record_errors,711 );712 }713714 // Process renders715 for render in &renders {716 if should_record_errors {717 state.render(render.index, render.place.identifier, env);718 }719 }720721 // Collect function effects for context vars and params722 // NOTE: TS iterates [...fn.context, ...fn.params] — context first, then params723 for ctx in &func.context {724 collect_param_effects(&state, ctx, &mut function_effects);725 }726 for param in &func.params {727 let place = match param {728 react_compiler_hir::ParamPattern::Place(p) => p,729 react_compiler_hir::ParamPattern::Spread(s) => &s.place,730 };731 collect_param_effects(&state, place, &mut function_effects);732 }733734 // Set effect on mutated params/context vars735 // We need to do this in a separate pass because we need to know which params736 // were mutated before setting effects737 let mut captured_params: FxHashSet<IdentifierId> = FxHashSet::default();738 for param in &func.params {739 let place = match param {740 react_compiler_hir::ParamPattern::Place(p) => p,741 react_compiler_hir::ParamPattern::Spread(s) => &s.place,742 };743 if let Some(node) = state.nodes.get(&place.identifier) {744 if node.local.is_some() || node.transitive.is_some() {745 captured_params.insert(place.identifier);746 }747 }748 }749 for ctx in &func.context {750 if let Some(node) = state.nodes.get(&ctx.identifier) {751 if node.local.is_some() || node.transitive.is_some() {752 captured_params.insert(ctx.identifier);753 }754 }755 }756757 // Now mutate the effects on params/context in place758 for param in &mut func.params {759 let place = match param {760 react_compiler_hir::ParamPattern::Place(p) => p,761 react_compiler_hir::ParamPattern::Spread(s) => &mut s.place,762 };763 if captured_params.contains(&place.identifier) {764 place.effect = Effect::Capture;765 }766 }767 for ctx in &mut func.context {768 if captured_params.contains(&ctx.identifier) {769 ctx.effect = Effect::Capture;770 }771 }772773 // =========================================================================774 // Part 2: Add legacy operand-specific effects based on instruction effects775 // and mutable ranges. Also fix up mutable range start values.776 // =========================================================================777 // Part 2 loop778 for &block_id in &block_order {779 let block = &func.body.blocks[&block_id];780781 // Process phis782 let phi_data: Vec<_> = block783 .phis784 .iter()785 .map(|phi| {786 let first_instr_id = block787 .instructions788 .first()789 .map(|id| func.instructions[id.0 as usize].id)790 .unwrap_or_else(|| block.terminal.evaluation_order());791792 let is_mutated_after_creation = env.identifiers[phi.place.identifier.0 as usize]793 .mutable_range794 .end795 > first_instr_id;796797 (798 phi.place.identifier,799 phi.operands800 .values()801 .map(|o| o.identifier)802 .collect::<Vec<_>>(),803 is_mutated_after_creation,804 first_instr_id,805 )806 })807 .collect();808809 for (phi_id, _operand_ids, is_mutated_after_creation, first_instr_id) in &phi_data {810 // Set phi place effect to Store811 // We need to find this phi in the block and set it812 let block = func.body.blocks.get_mut(&block_id).unwrap();813 for phi in &mut block.phis {814 if phi.place.identifier == *phi_id {815 phi.place.effect = Effect::Store;816 for operand in phi.operands.values_mut() {817 operand.effect = if *is_mutated_after_creation {818 Effect::Capture819 } else {820 Effect::Read821 };822 }823 break;824 }825 }826827 if *is_mutated_after_creation {828 let ident = &mut env.identifiers[phi_id.0 as usize];829 if ident.mutable_range.start == EvaluationOrder(0) {830 ident.mutable_range.start = EvaluationOrder(first_instr_id.0.saturating_sub(1));831 }832 }833 }834835 let block = &func.body.blocks[&block_id];836 let instr_ids: Vec<_> = block.instructions.clone();837838 for instr_id in &instr_ids {839 let instr = &func.instructions[instr_id.0 as usize];840 let eval_order = instr.id;841842 // Set lvalue effect to ConditionallyMutate and fix up mutable range843 // This covers the top-level lvalue844 let lvalue_id = instr.lvalue.identifier;845 {846 let ident = &mut env.identifiers[lvalue_id.0 as usize];847 if ident.mutable_range.start == EvaluationOrder(0) {848 ident.mutable_range.start = eval_order;849 }850 if ident.mutable_range.end == EvaluationOrder(0) {851 ident.mutable_range.end =852 EvaluationOrder((eval_order.0 + 1).max(ident.mutable_range.end.0));853 }854 }855 func.instructions[instr_id.0 as usize].lvalue.effect = Effect::ConditionallyMutate;856857 // Also handle value-level lvalues (DeclareLocal, StoreLocal, etc.)858 let value_lvalue_ids: Vec<IdentifierId> =859 each_instruction_value_lvalue(&func.instructions[instr_id.0 as usize].value)860 .into_iter()861 .map(|p| p.identifier)862 .collect();863 for vlid in &value_lvalue_ids {864 let ident = &mut env.identifiers[vlid.0 as usize];865 if ident.mutable_range.start == EvaluationOrder(0) {866 ident.mutable_range.start = eval_order;867 }868 if ident.mutable_range.end == EvaluationOrder(0) {869 ident.mutable_range.end =870 EvaluationOrder((eval_order.0 + 1).max(ident.mutable_range.end.0));871 }872 }873 for_each_instruction_value_lvalue_mut(874 &mut func.instructions[instr_id.0 as usize].value,875 &mut |place| {876 place.effect = Effect::ConditionallyMutate;877 },878 );879880 // Set operand effects to Read881 for_each_instruction_value_operand_mut(882 &mut func.instructions[instr_id.0 as usize].value,883 &mut |place| {884 place.effect = Effect::Read;885 },886 );887888 let instr = &func.instructions[instr_id.0 as usize];889 if instr.effects.is_none() {890 continue;891 }892893 // Compute operand effects from instruction effects894 let effects = instr.effects.as_ref().unwrap().clone();895 let mut operand_effects: FxHashMap<IdentifierId, Effect> = FxHashMap::default();896897 for effect in &effects {898 match effect {899 AliasingEffect::Assign { from, into, .. }900 | AliasingEffect::Alias { from, into }901 | AliasingEffect::Capture { from, into }902 | AliasingEffect::CreateFrom { from, into }903 | AliasingEffect::MaybeAlias { from, into } => {904 let is_mutated_or_reassigned = env.identifiers[into.identifier.0 as usize]905 .mutable_range906 .end907 > eval_order;908 if is_mutated_or_reassigned {909 operand_effects.insert(from.identifier, Effect::Capture);910 operand_effects.insert(into.identifier, Effect::Store);911 } else {912 operand_effects.insert(from.identifier, Effect::Read);913 operand_effects.insert(into.identifier, Effect::Store);914 }915 }916 AliasingEffect::CreateFunction { .. } | AliasingEffect::Create { .. } => {917 // no-op918 }919 AliasingEffect::Mutate { value, .. } => {920 operand_effects.insert(value.identifier, Effect::Store);921 }922 AliasingEffect::Apply { .. } => {923 return Err(CompilerDiagnostic::new(924 ErrorCategory::Invariant,925 "[AnalyzeFunctions] Expected Apply effects to be replaced with more precise effects",926 None,927 ));928 }929 AliasingEffect::MutateTransitive { value, .. }930 | AliasingEffect::MutateConditionally { value }931 | AliasingEffect::MutateTransitiveConditionally { value } => {932 operand_effects.insert(value.identifier, Effect::ConditionallyMutate);933 }934 AliasingEffect::Freeze { value, .. } => {935 operand_effects.insert(value.identifier, Effect::Freeze);936 }937 AliasingEffect::ImmutableCapture { .. } => {938 // no-op, Read is the default939 }940 AliasingEffect::Impure { .. }941 | AliasingEffect::Render { .. }942 | AliasingEffect::MutateFrozen { .. }943 | AliasingEffect::MutateGlobal { .. } => {944 // no-op945 }946 }947 }948949 // Apply operand effects to top-level lvalue950 let instr = &mut func.instructions[instr_id.0 as usize];951 let lvalue_id = instr.lvalue.identifier;952 if let Some(&effect) = operand_effects.get(&lvalue_id) {953 instr.lvalue.effect = effect;954 }955 // Apply operand effects to value-level lvalues956 for_each_instruction_value_lvalue_mut(&mut instr.value, &mut |place| {957 if let Some(&effect) = operand_effects.get(&place.identifier) {958 place.effect = effect;959 }960 });961962 // Apply operand effects to value operands and fix up mutable ranges963 {964 let mut apply = |place: &mut Place| {965 // Fix up mutable range start966 let ident = &env.identifiers[place.identifier.0 as usize];967 if ident.mutable_range.end > eval_order968 && ident.mutable_range.start == EvaluationOrder(0)969 {970 env.identifiers[place.identifier.0 as usize]971 .mutable_range972 .start = eval_order;973 }974 // Apply effect975 if let Some(&effect) = operand_effects.get(&place.identifier) {976 place.effect = effect;977 }978 };979 for_each_instruction_value_operand_mut(&mut instr.value, &mut apply);980981 // FunctionExpression/ObjectMethod context variables are operands that982 // require env access (they live in env.functions[func_id].context).983 if let InstructionValue::FunctionExpression { lowered_func, .. }984 | InstructionValue::ObjectMethod { lowered_func, .. } = &instr.value985 {986 let func_id = lowered_func.func;987 let ctx_ids: Vec<IdentifierId> = env.functions[func_id.0 as usize]988 .context989 .iter()990 .map(|c| c.identifier)991 .collect();992 for ctx_id in &ctx_ids {993 let ident = &env.identifiers[ctx_id.0 as usize];994 if ident.mutable_range.end > eval_order995 && ident.mutable_range.start == EvaluationOrder(0)996 {997 env.identifiers[ctx_id.0 as usize].mutable_range.start = eval_order;998 }999 let effect = operand_effects.get(ctx_id).copied().unwrap_or(Effect::Read);1000 let inner_func = &mut env.functions[func_id.0 as usize];1001 for ctx_place in &mut inner_func.context {1002 if ctx_place.identifier == *ctx_id {1003 ctx_place.effect = effect;1004 }1005 }1006 }1007 }1008 }10091010 // Handle StoreContext case: extend rvalue range if needed1011 let instr = &func.instructions[instr_id.0 as usize];1012 if let InstructionValue::StoreContext { value, .. } = &instr.value {1013 let val_id = value.identifier;1014 let val_range_end = env.identifiers[val_id.0 as usize].mutable_range.end;1015 if val_range_end <= eval_order {1016 env.identifiers[val_id.0 as usize].mutable_range.end =1017 EvaluationOrder(eval_order.0 + 1);1018 }1019 }1020 }10211022 // Set terminal operand effects1023 let block = func.body.blocks.get_mut(&block_id).unwrap();1024 match &mut block.terminal {1025 react_compiler_hir::Terminal::Return { value, .. } => {1026 value.effect = if is_function_expression {1027 Effect::Read1028 } else {1029 Effect::Freeze1030 };1031 }1032 terminal => {1033 for_each_terminal_operand_mut(terminal, &mut |place| {1034 place.effect = Effect::Read;1035 });1036 }1037 }1038 }10391040 // =========================================================================1041 // Part 3: Finish populating the externally visible effects1042 // =========================================================================1043 let returns_id = func.returns.identifier;1044 let returns_type_id = env.identifiers[returns_id.0 as usize].type_;1045 let returns_type = &env.types[returns_type_id.0 as usize];1046 let return_value_kind = if is_primitive_type(returns_type) {1047 ValueKind::Primitive1048 } else if is_jsx_type(returns_type) {1049 ValueKind::Frozen1050 } else {1051 ValueKind::Mutable1052 };10531054 function_effects.push(AliasingEffect::Create {1055 into: func.returns.clone(),1056 value: return_value_kind,1057 reason: ValueReason::KnownReturnSignature,1058 });10591060 // Determine precise data-flow effects by simulating transitive mutations1061 let mut tracked: Vec<Place> = Vec::new();1062 for param in &func.params {1063 let place = match param {1064 react_compiler_hir::ParamPattern::Place(p) => p.clone(),1065 react_compiler_hir::ParamPattern::Spread(s) => s.place.clone(),1066 };1067 tracked.push(place);1068 }1069 for ctx in &func.context {1070 tracked.push(ctx.clone());1071 }1072 tracked.push(func.returns.clone());10731074 let returns_identifier_id = func.returns.identifier;10751076 for i in 0..tracked.len() {1077 let into = tracked[i].clone();1078 let mutation_index = index;1079 index += 1;10801081 state.mutate(1082 mutation_index,1083 into.identifier,1084 None, // simulated mutation1085 true,1086 MutationKind::Conditional,1087 into.loc,1088 None,1089 env,1090 false, // never record errors for simulated mutations1091 );10921093 for j in 0..tracked.len() {1094 let from = &tracked[j];1095 if from.identifier == into.identifier || from.identifier == returns_identifier_id {1096 continue;1097 }10981099 let from_node = state.nodes.get(&from.identifier);1100 assert!(1101 from_node.is_some(),1102 "Expected a node to exist for all parameters and context variables"1103 );1104 let from_node = from_node.unwrap();11051106 if from_node.last_mutated == mutation_index {1107 if into.identifier == returns_identifier_id {1108 function_effects.push(AliasingEffect::Alias {1109 from: from.clone(),1110 into: into.clone(),1111 });1112 } else {1113 function_effects.push(AliasingEffect::Capture {1114 from: from.clone(),1115 into: into.clone(),1116 });1117 }1118 }1119 }1120 }11211122 Ok(function_effects)1123}11241125// =============================================================================1126// Helper: collect param/context mutation effects1127// =============================================================================11281129fn collect_param_effects(1130 state: &AliasingState,1131 place: &Place,1132 function_effects: &mut Vec<AliasingEffect>,1133) {1134 let node = match state.nodes.get(&place.identifier) {1135 Some(n) => n,1136 None => return,1137 };11381139 if let Some(ref local) = node.local {1140 match local.kind {1141 MutationKind::Conditional => {1142 function_effects.push(AliasingEffect::MutateConditionally {1143 value: Place {1144 loc: local.loc,1145 ..place.clone()1146 },1147 });1148 }1149 MutationKind::Definite => {1150 function_effects.push(AliasingEffect::Mutate {1151 value: Place {1152 loc: local.loc,1153 ..place.clone()1154 },1155 reason: node.mutation_reason.clone(),1156 });1157 }1158 MutationKind::None => {}1159 }1160 }11611162 if let Some(ref transitive) = node.transitive {1163 match transitive.kind {1164 MutationKind::Conditional => {1165 function_effects.push(AliasingEffect::MutateTransitiveConditionally {1166 value: Place {1167 loc: transitive.loc,1168 ..place.clone()1169 },1170 });1171 }1172 MutationKind::Definite => {1173 function_effects.push(AliasingEffect::MutateTransitive {1174 value: Place {1175 loc: transitive.loc,1176 ..place.clone()1177 },1178 });1179 }1180 MutationKind::None => {}1181 }1182 }1183}
Code quality findings 79
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
self.nodes.get_mut(&from_id).unwrap().edges.push(Edge {
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
.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
self.nodes.get_mut(&from_id).unwrap().edges.push(Edge {
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
.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
self.nodes.get_mut(&from_id).unwrap().edges.push(Edge {
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
.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 ident = &mut env.identifiers[node.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[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
let block = &func.body.blocks[&block_id];
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 block = &func.body.blocks[&block_id];
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
// NOTE: TS iterates [...fn.context, ...fn.params] — context first, then params
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 block = &func.body.blocks[&block_id];
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
.map(|id| func.instructions[id.0 as usize].id)
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 is_mutated_after_creation = env.identifiers[phi.place.identifier.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 ident = &mut env.identifiers[phi_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 block = &func.body.blocks[&block_id];
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 ident = &mut env.identifiers[lvalue_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
func.instructions[instr_id.0 as usize].lvalue.effect = Effect::ConditionallyMutate;
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
each_instruction_value_lvalue(&func.instructions[instr_id.0 as usize].value)
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 ident = &mut env.identifiers[vlid.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 func.instructions[instr_id.0 as usize].value,
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 func.instructions[instr_id.0 as usize].value,
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: '.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 effects = instr.effects.as_ref().unwrap().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 is_mutated_or_reassigned = env.identifiers[into.identifier.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 ident = &env.identifiers[place.identifier.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[place.identifier.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
// require env access (they live in env.functions[func_id].context).
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 ctx_ids: Vec<IdentifierId> = 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 ident = &env.identifiers[ctx_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[ctx_id.0 as usize].mutable_range.start = eval_order;
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 = &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 val_range_end = env.identifiers[val_id.0 as usize].mutable_range.end;
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[val_id.0 as usize].mutable_range.end =
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 returns_type_id = env.identifiers[returns_id.0 as usize].type_;
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 returns_type = &env.types[returns_type_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 into = tracked[i].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 from = &tracked[j];
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 from_node = from_node.unwrap();
Info: Usage of `#[allow(...)]` suppresses compiler lints. Ensure the allowance is justified, well-scoped, and ideally temporary. Overuse can hide potential issues.
info
maintainability
allow-lint
#[allow(dead_code)]
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
queue.push(alias);
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
queue.push(alias);
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
queue.push(capture);
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
let node_value_kind = match &node.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
queue.push(QueueEntry {
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
queue.push(QueueEntry {
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
queue.push(QueueEntry {
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
queue.push(QueueEntry {
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
queue.push(QueueEntry {
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
.filter_map(|effect| match effect {
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
| AliasingEffect::MutateGlobal { error, .. } => Some(error.clone()),
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
.push(PendingPhiOperand {
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
from: operand.clone(),
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
into: phi.place.clone(),
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<_> = block.instructions.clone();
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
Some(e) => e.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 effect {
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
let terminal_effects = match terminal {
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
| react_compiler_hir::Terminal::Return { effects, .. } => effects.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 effect {
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
mutation.reason.clone(),
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<_> = block.instructions.clone();
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 effects = instr.effects.as_ref().unwrap().clone();
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
function_effects.push(AliasingEffect::Create {
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
into: func.returns.clone(),
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
react_compiler_hir::ParamPattern::Place(p) => p.clone(),
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
react_compiler_hir::ParamPattern::Spread(s) => s.place.clone(),
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
tracked.push(place);
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
tracked.push(ctx.clone());
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
tracked.push(ctx.clone());
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
tracked.push(func.returns.clone());
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
tracked.push(func.returns.clone());
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 into = tracked[i].clone();