compiler/crates/react_compiler_inference/src/infer_mutation_aliasing_ranges.rs RUST 1,184 lines View on github.com → Search inside
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(&current) {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(&current).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(&current) {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();

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.