compiler/crates/react_compiler_optimization/src/constant_propagation.rs RUST 1,115 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//! Constant propagation/folding pass.7//!8//! Applies Sparse Conditional Constant Propagation to the given function.9//! We use abstract interpretation to record known constant values for identifiers,10//! with lack of a value indicating that the identifier does not have a known11//! constant value.12//!13//! Instructions which can be compile-time evaluated *and* whose operands are known14//! constants are replaced with the resulting constant value.15//!16//! This pass also exploits SSA form, tracking constant values of local variables.17//! For example, in `let x = 4; let y = x + 1` we know that `x = 4` in the binary18//! expression and can replace it with `Constant 5`.19//!20//! This pass also visits conditionals (currently only IfTerminal) and can prune21//! unreachable branches when the condition is a known truthy/falsey constant.22//! The pass uses fixpoint iteration, looping until no additional updates can be23//! performed.24//!25//! Analogous to TS `Optimization/ConstantPropagation.ts`.2627use rustc_hash::FxHashMap;2829use react_compiler_diagnostics::JsString;30use react_compiler_hir::environment::Environment;31use react_compiler_hir::{32    BinaryOperator, BlockKind, FloatValue, FunctionId, GotoVariant, HirFunction, IdentifierId,33    InstructionValue, NonLocalBinding, Phi, Place, PrimitiveValue, PropertyLiteral, SourceLocation,34    Terminal, UnaryOperator, UpdateOperator, format_js_number,35};36use react_compiler_lowering::{37    get_reverse_postordered_blocks, mark_instruction_ids, mark_predecessors,38    remove_dead_do_while_statements, remove_unnecessary_try_catch, remove_unreachable_for_updates,39};40use react_compiler_ssa::enter_ssa::placeholder_function;4142use crate::merge_consecutive_blocks::merge_consecutive_blocks;4344// =============================================================================45// Constant type — mirrors TS `type Constant = Primitive | LoadGlobal`46// The loc is preserved so that when we replace an instruction value with the47// constant, we use the loc from the original definition site (matching TS).48// =============================================================================4950#[derive(Debug, Clone)]51enum Constant {52    Primitive {53        value: PrimitiveValue,54        loc: Option<SourceLocation>,55    },56    LoadGlobal {57        binding: NonLocalBinding,58        loc: Option<SourceLocation>,59    },60}6162impl Constant {63    fn into_instruction_value(self) -> InstructionValue {64        match self {65            Constant::Primitive { value, loc } => InstructionValue::Primitive { value, loc },66            Constant::LoadGlobal { binding, loc } => InstructionValue::LoadGlobal { binding, loc },67        }68    }69}7071/// Map of known constant values. Uses FxHashMap (not IndexMap) since iteration72/// order does not affect correctness — this map is only used for lookups.73type Constants = FxHashMap<IdentifierId, Constant>;7475// =============================================================================76// Public entry point77// =============================================================================7879pub fn constant_propagation(func: &mut HirFunction, env: &mut Environment) {80    let mut constants: Constants = FxHashMap::default();81    constant_propagation_impl(func, env, &mut constants);82}8384fn constant_propagation_impl(85    func: &mut HirFunction,86    env: &mut Environment,87    constants: &mut Constants,88) {89    loop {90        let have_terminals_changed = apply_constant_propagation(func, env, constants);91        if !have_terminals_changed {92            break;93        }94        /*95         * If terminals have changed then blocks may have become newly unreachable.96         * Re-run minification of the graph (incl reordering instruction ids)97         */98        func.body.blocks = get_reverse_postordered_blocks(&func.body, &func.instructions);99        remove_unreachable_for_updates(&mut func.body);100        remove_dead_do_while_statements(&mut func.body);101        remove_unnecessary_try_catch(&mut func.body);102        mark_instruction_ids(&mut func.body, &mut func.instructions);103        mark_predecessors(&mut func.body);104105        // Now that predecessors are updated, prune phi operands that can never be reached106        for (_block_id, block) in func.body.blocks.iter_mut() {107            for phi in &mut block.phis {108                phi.operands109                    .retain(|pred, _operand| block.preds.contains(pred));110            }111        }112113        /*114         * By removing some phi operands, there may be phis that were not previously115         * redundant but now are116         */117        react_compiler_ssa::eliminate_redundant_phi(func, env);118119        /*120         * Finally, merge together any blocks that are now guaranteed to execute121         * consecutively122         */123        merge_consecutive_blocks(func, &mut env.functions);124125        // TODO: port assertConsistentIdentifiers(fn) and assertTerminalSuccessorsExist(fn)126        // from TS HIR validation. These are debug assertions that verify structural127        // invariants after the CFG cleanup helpers run.128    }129}130131fn apply_constant_propagation(132    func: &mut HirFunction,133    env: &mut Environment,134    constants: &mut Constants,135) -> bool {136    let mut has_changes = false;137138    let block_ids: Vec<_> = func.body.blocks.keys().copied().collect();139    for block_id in block_ids {140        let block = &func.body.blocks[&block_id];141142        // Initialize phi values if all operands have the same known constant value143        let phi_updates: Vec<(IdentifierId, Constant)> = block144            .phis145            .iter()146            .filter_map(|phi| {147                let value = evaluate_phi(phi, constants)?;148                Some((phi.place.identifier, value))149            })150            .collect();151        for (id, value) in phi_updates {152            constants.insert(id, value);153        }154155        let block = &func.body.blocks[&block_id];156        let instr_ids = block.instructions.clone();157        let block_kind = block.kind;158        let instr_count = instr_ids.len();159160        for (i, instr_id) in instr_ids.iter().enumerate() {161            if block_kind == BlockKind::Sequence && i == instr_count - 1 {162                /*163                 * evaluating the last value of a value block can break order of evaluation,164                 * skip these instructions165                 */166                continue;167            }168            let result = evaluate_instruction(constants, func, env, *instr_id);169            if let Some(value) = result {170                let lvalue_id = func.instructions[instr_id.0 as usize].lvalue.identifier;171                constants.insert(lvalue_id, value);172            }173        }174175        let block = &func.body.blocks[&block_id];176        match &block.terminal {177            Terminal::If {178                test,179                consequent,180                alternate,181                id,182                loc,183                ..184            } => {185                let test_value = read(constants, test);186                if let Some(Constant::Primitive {187                    value: ref prim, ..188                }) = test_value189                {190                    has_changes = true;191                    let target_block_id = if is_truthy(prim) {192                        *consequent193                    } else {194                        *alternate195                    };196                    let terminal = Terminal::Goto {197                        variant: GotoVariant::Break,198                        block: target_block_id,199                        id: *id,200                        loc: *loc,201                    };202                    func.body.blocks.get_mut(&block_id).unwrap().terminal = terminal;203                }204            }205            Terminal::Unsupported { .. }206            | Terminal::Unreachable { .. }207            | Terminal::Throw { .. }208            | Terminal::Return { .. }209            | Terminal::Goto { .. }210            | Terminal::Branch { .. }211            | Terminal::Switch { .. }212            | Terminal::DoWhile { .. }213            | Terminal::While { .. }214            | Terminal::For { .. }215            | Terminal::ForOf { .. }216            | Terminal::ForIn { .. }217            | Terminal::Logical { .. }218            | Terminal::Ternary { .. }219            | Terminal::Optional { .. }220            | Terminal::Label { .. }221            | Terminal::Sequence { .. }222            | Terminal::MaybeThrow { .. }223            | Terminal::Try { .. }224            | Terminal::Scope { .. }225            | Terminal::PrunedScope { .. } => {226                // no-op227            }228        }229    }230231    has_changes232}233234// =============================================================================235// Phi evaluation236// =============================================================================237238fn evaluate_phi(phi: &Phi, constants: &Constants) -> Option<Constant> {239    let mut value: Option<Constant> = None;240    for (_pred, operand) in &phi.operands {241        let operand_value = constants.get(&operand.identifier)?;242243        match &value {244            None => {245                // first iteration of the loop246                value = Some(operand_value.clone());247                continue;248            }249            Some(current) => match (current, operand_value) {250                (Constant::Primitive { value: a, .. }, Constant::Primitive { value: b, .. }) => {251                    // Use JS strict equality semantics: NaN !== NaN252                    if !js_strict_equal(a, b) {253                        return None;254                    }255                }256                (257                    Constant::LoadGlobal { binding: a, .. },258                    Constant::LoadGlobal { binding: b, .. },259                ) => {260                    // different global values, can't constant propagate261                    if a.name() != b.name() {262                        return None;263                    }264                }265                // found different kinds of constants, can't constant propagate266                (Constant::Primitive { .. }, Constant::LoadGlobal { .. })267                | (Constant::LoadGlobal { .. }, Constant::Primitive { .. }) => {268                    return None;269                }270            },271        }272    }273    value274}275276// =============================================================================277// Instruction evaluation278// =============================================================================279280fn evaluate_instruction(281    constants: &mut Constants,282    func: &mut HirFunction,283    env: &mut Environment,284    instr_id: react_compiler_hir::InstructionId,285) -> Option<Constant> {286    let instr = &func.instructions[instr_id.0 as usize];287    match &instr.value {288        InstructionValue::Primitive { value, loc } => Some(Constant::Primitive {289            value: value.clone(),290            loc: *loc,291        }),292        InstructionValue::LoadGlobal { binding, loc } => Some(Constant::LoadGlobal {293            binding: binding.clone(),294            loc: *loc,295        }),296        InstructionValue::ComputedLoad {297            object,298            property,299            loc,300        } => {301            let prop_value = read(constants, property);302            if let Some(Constant::Primitive {303                value: ref prim, ..304            }) = prop_value305            {306                match prim {307                    PrimitiveValue::String(s) if s.as_str().is_some_and(is_valid_identifier) => {308                        let object = object.clone();309                        let loc = *loc;310                        let new_property =311                            PropertyLiteral::String(s.as_str().expect("guarded utf8").to_string());312                        func.instructions[instr_id.0 as usize].value =313                            InstructionValue::PropertyLoad {314                                object,315                                property: new_property,316                                loc,317                            };318                    }319                    PrimitiveValue::Number(n) => {320                        let object = object.clone();321                        let loc = *loc;322                        let new_property = PropertyLiteral::Number(*n);323                        func.instructions[instr_id.0 as usize].value =324                            InstructionValue::PropertyLoad {325                                object,326                                property: new_property,327                                loc,328                            };329                    }330                    PrimitiveValue::Null331                    | PrimitiveValue::Undefined332                    | PrimitiveValue::Boolean(_)333                    | PrimitiveValue::String(_) => {}334                }335            }336            None337        }338        InstructionValue::ComputedStore {339            object,340            property,341            value,342            loc,343        } => {344            let prop_value = read(constants, property);345            if let Some(Constant::Primitive {346                value: ref prim, ..347            }) = prop_value348            {349                match prim {350                    PrimitiveValue::String(s) if s.as_str().is_some_and(is_valid_identifier) => {351                        let object = object.clone();352                        let store_value = value.clone();353                        let loc = *loc;354                        let new_property =355                            PropertyLiteral::String(s.as_str().expect("guarded utf8").to_string());356                        func.instructions[instr_id.0 as usize].value =357                            InstructionValue::PropertyStore {358                                object,359                                property: new_property,360                                value: store_value,361                                loc,362                            };363                    }364                    PrimitiveValue::Number(n) => {365                        let object = object.clone();366                        let store_value = value.clone();367                        let loc = *loc;368                        let new_property = PropertyLiteral::Number(*n);369                        func.instructions[instr_id.0 as usize].value =370                            InstructionValue::PropertyStore {371                                object,372                                property: new_property,373                                value: store_value,374                                loc,375                            };376                    }377                    PrimitiveValue::Null378                    | PrimitiveValue::Undefined379                    | PrimitiveValue::Boolean(_)380                    | PrimitiveValue::String(_) => {}381                }382            }383            None384        }385        InstructionValue::PostfixUpdate {386            lvalue,387            operation,388            value,389            loc,390        } => {391            let previous = read(constants, value);392            if let Some(Constant::Primitive {393                value: PrimitiveValue::Number(n),394                loc: prev_loc,395            }) = previous396            {397                let prev_val = n.value();398                let next_val = match operation {399                    UpdateOperator::Increment => prev_val + 1.0,400                    UpdateOperator::Decrement => prev_val - 1.0,401                };402                // Store the updated value for the lvalue403                let lvalue_id = lvalue.identifier;404                constants.insert(405                    lvalue_id,406                    Constant::Primitive {407                        value: PrimitiveValue::Number(FloatValue::new(next_val)),408                        loc: *loc,409                    },410                );411                // But return the value prior to the update (preserving its original loc)412                return Some(Constant::Primitive {413                    value: PrimitiveValue::Number(n),414                    loc: prev_loc,415                });416            }417            None418        }419        InstructionValue::PrefixUpdate {420            lvalue,421            operation,422            value,423            loc,424        } => {425            let previous = read(constants, value);426            if let Some(Constant::Primitive {427                value: PrimitiveValue::Number(n),428                ..429            }) = previous430            {431                let prev_val = n.value();432                let next_val = match operation {433                    UpdateOperator::Increment => prev_val + 1.0,434                    UpdateOperator::Decrement => prev_val - 1.0,435                };436                let result = Constant::Primitive {437                    value: PrimitiveValue::Number(FloatValue::new(next_val)),438                    loc: *loc,439                };440                // Store and return the updated value441                let lvalue_id = lvalue.identifier;442                constants.insert(lvalue_id, result.clone());443                return Some(result);444            }445            None446        }447        InstructionValue::UnaryExpression {448            operator,449            value,450            loc,451        } => match operator {452            UnaryOperator::Not => {453                let operand = read(constants, value);454                if let Some(Constant::Primitive {455                    value: ref prim, ..456                }) = operand457                {458                    let negated = !is_truthy(prim);459                    let loc = *loc;460                    let result = Constant::Primitive {461                        value: PrimitiveValue::Boolean(negated),462                        loc,463                    };464                    func.instructions[instr_id.0 as usize].value = InstructionValue::Primitive {465                        value: PrimitiveValue::Boolean(negated),466                        loc,467                    };468                    return Some(result);469                }470                None471            }472            UnaryOperator::Minus => {473                let operand = read(constants, value);474                if let Some(Constant::Primitive {475                    value: PrimitiveValue::Number(n),476                    ..477                }) = operand478                {479                    let negated = n.value() * -1.0;480                    let loc = *loc;481                    let result = Constant::Primitive {482                        value: PrimitiveValue::Number(FloatValue::new(negated)),483                        loc,484                    };485                    func.instructions[instr_id.0 as usize].value = InstructionValue::Primitive {486                        value: PrimitiveValue::Number(FloatValue::new(negated)),487                        loc,488                    };489                    return Some(result);490                }491                None492            }493            UnaryOperator::Plus494            | UnaryOperator::BitwiseNot495            | UnaryOperator::TypeOf496            | UnaryOperator::Void => None,497        },498        InstructionValue::BinaryExpression {499            operator,500            left,501            right,502            loc,503        } => {504            let lhs_value = read(constants, left);505            let rhs_value = read(constants, right);506            if let (507                Some(Constant::Primitive { value: lhs, .. }),508                Some(Constant::Primitive { value: rhs, .. }),509            ) = (&lhs_value, &rhs_value)510            {511                let result = evaluate_binary_op(*operator, lhs, rhs);512                if let Some(ref prim) = result {513                    let loc = *loc;514                    func.instructions[instr_id.0 as usize].value = InstructionValue::Primitive {515                        value: prim.clone(),516                        loc,517                    };518                    return Some(Constant::Primitive {519                        value: prim.clone(),520                        loc,521                    });522                }523            }524            None525        }526        InstructionValue::PropertyLoad {527            object,528            property,529            loc,530        } => {531            let object_value = read(constants, object);532            if let Some(Constant::Primitive {533                value: PrimitiveValue::String(ref s),534                ..535            }) = object_value536            {537                if let PropertyLiteral::String(prop_name) = property {538                    if prop_name == "length" {539                        // Use UTF-16 code unit count to match JS .length semantics540                        let len = s.len_utf16() as f64;541                        let loc = *loc;542                        let result = Constant::Primitive {543                            value: PrimitiveValue::Number(FloatValue::new(len)),544                            loc,545                        };546                        func.instructions[instr_id.0 as usize].value =547                            InstructionValue::Primitive {548                                value: PrimitiveValue::Number(FloatValue::new(len)),549                                loc,550                            };551                        return Some(result);552                    }553                }554            }555            None556        }557        InstructionValue::TemplateLiteral {558            subexprs,559            quasis,560            loc,561        } => {562            if subexprs.is_empty() {563                // No subexpressions: join all cooked quasis564                let mut result_string = String::new();565                for q in quasis {566                    match &q.cooked {567                        Some(cooked) => result_string.push_str(cooked),568                        None => return None,569                    }570                }571                let loc = *loc;572                let result = Constant::Primitive {573                    value: PrimitiveValue::String(JsString::from_marker_string(&result_string)),574                    loc,575                };576                func.instructions[instr_id.0 as usize].value = InstructionValue::Primitive {577                    value: PrimitiveValue::String(JsString::from_marker_string(&result_string)),578                    loc,579                };580                return Some(result);581            }582583            if subexprs.len() != quasis.len() - 1 {584                return None;585            }586587            if quasis.iter().any(|q| q.cooked.is_none()) {588                return None;589            }590591            let mut quasi_index = 0usize;592            let mut result_string = quasis[quasi_index].cooked.as_ref().unwrap().clone();593            quasi_index += 1;594595            for sub_expr in subexprs {596                let sub_expr_value = read(constants, sub_expr);597                let sub_prim = match sub_expr_value {598                    Some(Constant::Primitive { ref value, .. }) => value,599                    _ => return None,600                };601602                let expression_str = match sub_prim {603                    PrimitiveValue::Null => "null".to_string(),604                    PrimitiveValue::Boolean(b) => b.to_string(),605                    PrimitiveValue::Number(n) => format_js_number(n.value()),606                    PrimitiveValue::String(s) => s.to_marker_string(),607                    // TS rejects undefined subexpression values608                    PrimitiveValue::Undefined => return None,609                };610611                let suffix = match &quasis[quasi_index].cooked {612                    Some(s) => s.clone(),613                    None => return None,614                };615                quasi_index += 1;616617                result_string.push_str(&expression_str);618                result_string.push_str(&suffix);619            }620621            let loc = *loc;622            let result = Constant::Primitive {623                value: PrimitiveValue::String(JsString::from_marker_string(&result_string)),624                loc,625            };626            func.instructions[instr_id.0 as usize].value = InstructionValue::Primitive {627                value: PrimitiveValue::String(JsString::from_marker_string(&result_string)),628                loc,629            };630            Some(result)631        }632        InstructionValue::LoadLocal { place, .. } => {633            let place_value = read(constants, place);634            if let Some(ref constant) = place_value {635                // Replace the LoadLocal with the constant value (including the constant's original loc)636                func.instructions[instr_id.0 as usize].value =637                    constant.clone().into_instruction_value();638            }639            place_value640        }641        InstructionValue::StoreLocal { lvalue, value, .. } => {642            let place_value = read(constants, value);643            if let Some(ref constant) = place_value {644                let lvalue_id = lvalue.place.identifier;645                constants.insert(lvalue_id, constant.clone());646            }647            place_value648        }649        InstructionValue::FunctionExpression { lowered_func, .. } => {650            let func_id = lowered_func.func;651            process_inner_function(func_id, env, constants);652            None653        }654        InstructionValue::ObjectMethod { lowered_func, .. } => {655            let func_id = lowered_func.func;656            process_inner_function(func_id, env, constants);657            None658        }659        InstructionValue::StartMemoize { deps, .. } => {660            if let Some(deps) = deps {661                // Two-phase: collect which deps are constant, then mutate662                let const_dep_indices: Vec<usize> = deps663                    .iter()664                    .enumerate()665                    .filter_map(|(i, dep)| {666                        if let react_compiler_hir::ManualMemoDependencyRoot::NamedLocal {667                            value,668                            ..669                        } = &dep.root670                        {671                            let pv = read(constants, value);672                            if matches!(pv, Some(Constant::Primitive { .. })) {673                                return Some(i);674                            }675                        }676                        None677                    })678                    .collect();679                for idx in const_dep_indices {680                    if let InstructionValue::StartMemoize {681                        deps: Some(ref mut deps),682                        ..683                    } = func.instructions[instr_id.0 as usize].value684                    {685                        if let react_compiler_hir::ManualMemoDependencyRoot::NamedLocal {686                            constant,687                            ..688                        } = &mut deps[idx].root689                        {690                            *constant = true;691                        }692                    }693                }694            }695            None696        }697        // All other instruction kinds: no constant folding698        InstructionValue::LoadContext { .. }699        | InstructionValue::DeclareLocal { .. }700        | InstructionValue::DeclareContext { .. }701        | InstructionValue::StoreContext { .. }702        | InstructionValue::Destructure { .. }703        | InstructionValue::JSXText { .. }704        | InstructionValue::NewExpression { .. }705        | InstructionValue::CallExpression { .. }706        | InstructionValue::MethodCall { .. }707        | InstructionValue::TypeCastExpression { .. }708        | InstructionValue::JsxExpression { .. }709        | InstructionValue::ObjectExpression { .. }710        | InstructionValue::ArrayExpression { .. }711        | InstructionValue::JsxFragment { .. }712        | InstructionValue::RegExpLiteral { .. }713        | InstructionValue::MetaProperty { .. }714        | InstructionValue::PropertyStore { .. }715        | InstructionValue::PropertyDelete { .. }716        | InstructionValue::ComputedDelete { .. }717        | InstructionValue::StoreGlobal { .. }718        | InstructionValue::TaggedTemplateExpression { .. }719        | InstructionValue::Await { .. }720        | InstructionValue::GetIterator { .. }721        | InstructionValue::IteratorNext { .. }722        | InstructionValue::NextPropertyOf { .. }723        | InstructionValue::Debugger { .. }724        | InstructionValue::FinishMemoize { .. }725        | InstructionValue::UnsupportedNode { .. } => None,726    }727}728729// =============================================================================730// Inner function processing731// =============================================================================732733fn process_inner_function(func_id: FunctionId, env: &mut Environment, constants: &mut Constants) {734    let mut inner = std::mem::replace(735        &mut env.functions[func_id.0 as usize],736        placeholder_function(),737    );738    constant_propagation_impl(&mut inner, env, constants);739    env.functions[func_id.0 as usize] = inner;740}741742// =============================================================================743// Helper: read constant for a place744// =============================================================================745746fn read(constants: &Constants, place: &Place) -> Option<Constant> {747    constants.get(&place.identifier).cloned()748}749750// =============================================================================751// Helper: is_valid_identifier752// =============================================================================753754/// Check if a string is a valid JavaScript identifier.755/// Supports Unicode identifier characters per ECMAScript spec (ID_Start / ID_Continue).756/// Rejects JS reserved words (matching Babel's `isValidIdentifier` default behavior).757fn is_valid_identifier(s: &str) -> bool {758    if s.is_empty() {759        return false;760    }761    let mut chars = s.chars();762    match chars.next() {763        Some(c) if is_id_start(c) => {}764        _ => return false,765    }766    if !chars.all(is_id_continue) {767        return false;768    }769    !is_reserved_word(s)770}771772/// JS reserved words that cannot be used as identifiers.773/// Includes keywords, future reserved words, and strict mode reserved words.774fn is_reserved_word(s: &str) -> bool {775    matches!(776        s,777        "break"778            | "case"779            | "catch"780            | "continue"781            | "debugger"782            | "default"783            | "do"784            | "else"785            | "finally"786            | "for"787            | "function"788            | "if"789            | "in"790            | "instanceof"791            | "new"792            | "return"793            | "switch"794            | "this"795            | "throw"796            | "try"797            | "typeof"798            | "var"799            | "void"800            | "while"801            | "with"802            | "class"803            | "const"804            | "enum"805            | "export"806            | "extends"807            | "import"808            | "super"809            | "implements"810            | "interface"811            | "let"812            | "package"813            | "private"814            | "protected"815            | "public"816            | "static"817            | "yield"818            | "await"819            | "delete"820            | "null"821            | "true"822            | "false"823    )824}825826/// Check if a character is valid as the start of a JS identifier (ID_Start + _ + $).827fn is_id_start(c: char) -> bool {828    c == '_' || c == '$' || c.is_alphabetic()829}830831/// Check if a character is valid as a continuation of a JS identifier (ID_Continue + $ + \u200C + \u200D).832fn is_id_continue(c: char) -> bool {833    c == '$'834        || c == '_'835        || c.is_alphanumeric()836        || c == '\u{200C}' // ZWNJ837        || c == '\u{200D}' // ZWJ838}839840// =============================================================================841// Helper: is_truthy for PrimitiveValue842// =============================================================================843844fn is_truthy(value: &PrimitiveValue) -> bool {845    match value {846        PrimitiveValue::Null => false,847        PrimitiveValue::Undefined => false,848        PrimitiveValue::Boolean(b) => *b,849        PrimitiveValue::Number(n) => {850            let v = n.value();851            v != 0.0 && !v.is_nan()852        }853        PrimitiveValue::String(s) => s.len_utf16() != 0,854    }855}856857// =============================================================================858// Binary operation evaluation859// =============================================================================860861fn evaluate_binary_op(862    operator: BinaryOperator,863    lhs: &PrimitiveValue,864    rhs: &PrimitiveValue,865) -> Option<PrimitiveValue> {866    match operator {867        BinaryOperator::Add => match (lhs, rhs) {868            (PrimitiveValue::Number(l), PrimitiveValue::Number(r)) => Some(PrimitiveValue::Number(869                FloatValue::new(l.value() + r.value()),870            )),871            (PrimitiveValue::String(l), PrimitiveValue::String(r)) => {872                // Concatenate as code units: JS `+` can pair up surrogate873                // halves split across the operands.874                let mut units = l.code_units();875                units.extend(r.code_units());876                Some(PrimitiveValue::String(877                    react_compiler_diagnostics::JsString::from_code_units(units),878                ))879            }880            _ => None,881        },882        BinaryOperator::Subtract => match (lhs, rhs) {883            (PrimitiveValue::Number(l), PrimitiveValue::Number(r)) => Some(PrimitiveValue::Number(884                FloatValue::new(l.value() - r.value()),885            )),886            _ => None,887        },888        BinaryOperator::Multiply => match (lhs, rhs) {889            (PrimitiveValue::Number(l), PrimitiveValue::Number(r)) => Some(PrimitiveValue::Number(890                FloatValue::new(l.value() * r.value()),891            )),892            _ => None,893        },894        BinaryOperator::Divide => match (lhs, rhs) {895            (PrimitiveValue::Number(l), PrimitiveValue::Number(r)) => Some(PrimitiveValue::Number(896                FloatValue::new(l.value() / r.value()),897            )),898            _ => None,899        },900        BinaryOperator::Modulo => match (lhs, rhs) {901            (PrimitiveValue::Number(l), PrimitiveValue::Number(r)) => Some(PrimitiveValue::Number(902                FloatValue::new(l.value() % r.value()),903            )),904            _ => None,905        },906        BinaryOperator::Exponent => match (lhs, rhs) {907            (PrimitiveValue::Number(l), PrimitiveValue::Number(r)) => Some(PrimitiveValue::Number(908                FloatValue::new(l.value().powf(r.value())),909            )),910            _ => None,911        },912        BinaryOperator::BitwiseOr => match (lhs, rhs) {913            (PrimitiveValue::Number(l), PrimitiveValue::Number(r)) => {914                let result = js_to_int32(l.value()) | js_to_int32(r.value());915                Some(PrimitiveValue::Number(FloatValue::new(result as f64)))916            }917            _ => None,918        },919        BinaryOperator::BitwiseAnd => match (lhs, rhs) {920            (PrimitiveValue::Number(l), PrimitiveValue::Number(r)) => {921                let result = js_to_int32(l.value()) & js_to_int32(r.value());922                Some(PrimitiveValue::Number(FloatValue::new(result as f64)))923            }924            _ => None,925        },926        BinaryOperator::BitwiseXor => match (lhs, rhs) {927            (PrimitiveValue::Number(l), PrimitiveValue::Number(r)) => {928                let result = js_to_int32(l.value()) ^ js_to_int32(r.value());929                Some(PrimitiveValue::Number(FloatValue::new(result as f64)))930            }931            _ => None,932        },933        BinaryOperator::ShiftLeft => match (lhs, rhs) {934            (PrimitiveValue::Number(l), PrimitiveValue::Number(r)) => {935                let result = js_to_int32(l.value()) << (js_to_uint32(r.value()) & 0x1f);936                Some(PrimitiveValue::Number(FloatValue::new(result as f64)))937            }938            _ => None,939        },940        BinaryOperator::ShiftRight => match (lhs, rhs) {941            (PrimitiveValue::Number(l), PrimitiveValue::Number(r)) => {942                let result = js_to_int32(l.value()) >> (js_to_uint32(r.value()) & 0x1f);943                Some(PrimitiveValue::Number(FloatValue::new(result as f64)))944            }945            _ => None,946        },947        BinaryOperator::UnsignedShiftRight => match (lhs, rhs) {948            (PrimitiveValue::Number(l), PrimitiveValue::Number(r)) => {949                let result = js_to_uint32(l.value()) >> (js_to_uint32(r.value()) & 0x1f);950                Some(PrimitiveValue::Number(FloatValue::new(result as f64)))951            }952            _ => None,953        },954        BinaryOperator::LessThan => match (lhs, rhs) {955            (PrimitiveValue::Number(l), PrimitiveValue::Number(r)) => {956                Some(PrimitiveValue::Boolean(l.value() < r.value()))957            }958            _ => None,959        },960        BinaryOperator::LessEqual => match (lhs, rhs) {961            (PrimitiveValue::Number(l), PrimitiveValue::Number(r)) => {962                Some(PrimitiveValue::Boolean(l.value() <= r.value()))963            }964            _ => None,965        },966        BinaryOperator::GreaterThan => match (lhs, rhs) {967            (PrimitiveValue::Number(l), PrimitiveValue::Number(r)) => {968                Some(PrimitiveValue::Boolean(l.value() > r.value()))969            }970            _ => None,971        },972        BinaryOperator::GreaterEqual => match (lhs, rhs) {973            (PrimitiveValue::Number(l), PrimitiveValue::Number(r)) => {974                Some(PrimitiveValue::Boolean(l.value() >= r.value()))975            }976            _ => None,977        },978        BinaryOperator::StrictEqual => Some(PrimitiveValue::Boolean(js_strict_equal(lhs, rhs))),979        BinaryOperator::StrictNotEqual => Some(PrimitiveValue::Boolean(!js_strict_equal(lhs, rhs))),980        BinaryOperator::Equal => Some(PrimitiveValue::Boolean(js_abstract_equal(lhs, rhs))),981        BinaryOperator::NotEqual => Some(PrimitiveValue::Boolean(!js_abstract_equal(lhs, rhs))),982        BinaryOperator::In | BinaryOperator::InstanceOf => None,983    }984}985986// =============================================================================987// JavaScript equality semantics988// =============================================================================989990fn js_strict_equal(lhs: &PrimitiveValue, rhs: &PrimitiveValue) -> bool {991    match (lhs, rhs) {992        (PrimitiveValue::Null, PrimitiveValue::Null) => true,993        (PrimitiveValue::Undefined, PrimitiveValue::Undefined) => true,994        (PrimitiveValue::Boolean(a), PrimitiveValue::Boolean(b)) => a == b,995        (PrimitiveValue::Number(a), PrimitiveValue::Number(b)) => {996            let av = a.value();997            let bv = b.value();998            // NaN !== NaN in JS999            if av.is_nan() || bv.is_nan() {1000                return false;1001            }1002            av == bv1003        }1004        (PrimitiveValue::String(a), PrimitiveValue::String(b)) => a == b,1005        // Different types => false1006        _ => false,1007    }1008}10091010/// Convert a string to a number using JS `ToNumber` semantics.1011/// In JS: `""` → 0, `" "` → 0, `" 42 "` → 42, `"0x1A"` → 26, `"Infinity"` → Infinity.1012fn js_to_number(s: &str) -> f64 {1013    let trimmed = s.trim();1014    if trimmed.is_empty() {1015        return 0.0;1016    }1017    if trimmed == "Infinity" || trimmed == "+Infinity" {1018        return f64::INFINITY;1019    }1020    if trimmed == "-Infinity" {1021        return f64::NEG_INFINITY;1022    }1023    // Handle hex literals (0x/0X)1024    if trimmed.starts_with("0x") || trimmed.starts_with("0X") {1025        return match u64::from_str_radix(&trimmed[2..], 16) {1026            Ok(v) => v as f64,1027            Err(_) => f64::NAN,1028        };1029    }1030    // Handle octal literals (0o/0O)1031    if trimmed.starts_with("0o") || trimmed.starts_with("0O") {1032        return match u64::from_str_radix(&trimmed[2..], 8) {1033            Ok(v) => v as f64,1034            Err(_) => f64::NAN,1035        };1036    }1037    // Handle binary literals (0b/0B)1038    if trimmed.starts_with("0b") || trimmed.starts_with("0B") {1039        return match u64::from_str_radix(&trimmed[2..], 2) {1040            Ok(v) => v as f64,1041            Err(_) => f64::NAN,1042        };1043    }1044    trimmed.parse::<f64>().unwrap_or(f64::NAN)1045}10461047fn js_abstract_equal(lhs: &PrimitiveValue, rhs: &PrimitiveValue) -> bool {1048    match (lhs, rhs) {1049        (PrimitiveValue::Null, PrimitiveValue::Null) => true,1050        (PrimitiveValue::Undefined, PrimitiveValue::Undefined) => true,1051        (PrimitiveValue::Null, PrimitiveValue::Undefined)1052        | (PrimitiveValue::Undefined, PrimitiveValue::Null) => true,1053        (PrimitiveValue::Boolean(a), PrimitiveValue::Boolean(b)) => a == b,1054        (PrimitiveValue::Number(a), PrimitiveValue::Number(b)) => {1055            let av = a.value();1056            let bv = b.value();1057            if av.is_nan() || bv.is_nan() {1058                return false;1059            }1060            av == bv1061        }1062        (PrimitiveValue::String(a), PrimitiveValue::String(b)) => a == b,1063        // Cross-type coercions for primitives1064        (PrimitiveValue::Number(n), PrimitiveValue::String(s))1065        | (PrimitiveValue::String(s), PrimitiveValue::Number(n)) => {1066            // String is coerced to number using JS ToNumber semantics.1067            // Ill-formed strings coerce to NaN, like any non-numeric text.1068            let sv = match s.as_str() {1069                Some(utf8) => js_to_number(utf8),1070                None => f64::NAN,1071            };1072            let nv = n.value();1073            if nv.is_nan() || sv.is_nan() {1074                false1075            } else {1076                nv == sv1077            }1078        }1079        (PrimitiveValue::Boolean(b), other) => {1080            let num = if *b { 1.0 } else { 0.0 };1081            js_abstract_equal(&PrimitiveValue::Number(FloatValue::new(num)), other)1082        }1083        (other, PrimitiveValue::Boolean(b)) => {1084            let num = if *b { 1.0 } else { 0.0 };1085            js_abstract_equal(other, &PrimitiveValue::Number(FloatValue::new(num)))1086        }1087        // null/undefined vs number/string => false1088        _ => false,1089    }1090}10911092// =============================================================================1093// JavaScript Number.toString() approximation1094// =============================================================================10951096/// ECMAScript ToInt32: convert f64 to i32 with modular (wrapping) semantics.1097fn js_to_int32(n: f64) -> i32 {1098    if n.is_nan() || n.is_infinite() || n == 0.0 {1099        return 0;1100    }1101    // Truncate, then wrap to 32 bits1102    let int64 = (n.trunc() as i64) & 0xFFFFFFFF;1103    // Reinterpret as signed i321104    if int64 >= 0x80000000 {1105        (int64 as u32) as i321106    } else {1107        int64 as i321108    }1109}11101111/// ECMAScript ToUint32: convert f64 to u32 with modular (wrapping) semantics.1112fn js_to_uint32(n: f64) -> u32 {1113    js_to_int32(n) as u321114}

Code quality findings 53

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 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 lvalue_id = func.instructions[instr_id.0 as usize].lvalue.identifier;
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: '.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
func.body.blocks.get_mut(&block_id).unwrap().terminal = terminal;
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: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning correctness expect-usage
PropertyLiteral::String(s.as_str().expect("guarded utf8").to_string());
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].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
func.instructions[instr_id.0 as usize].value =
Warning: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning correctness expect-usage
PropertyLiteral::String(s.as_str().expect("guarded utf8").to_string());
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].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
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
func.instructions[instr_id.0 as usize].value = InstructionValue::Primitive {
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].value = InstructionValue::Primitive {
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].value = InstructionValue::Primitive {
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].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
func.instructions[instr_id.0 as usize].value = InstructionValue::Primitive {
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 mut result_string = quasis[quasi_index].cooked.as_ref().unwrap().clone();
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 mut result_string = quasis[quasi_index].cooked.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 suffix = match &quasis[quasi_index].cooked {
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].value = InstructionValue::Primitive {
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].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
} = 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 deps[idx].root
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 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
env.functions[func_id.0 as usize] = inner;
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
return match u64::from_str_radix(&trimmed[2..], 16) {
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
return match u64::from_str_radix(&trimmed[2..], 8) {
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
return match u64::from_str_radix(&trimmed[2..], 2) {
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 = 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
value = Some(operand_value.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 mut result_string = quasis[quasi_index].cooked.as_ref().unwrap().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
let sub_prim = match sub_expr_value {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
let expression_str = match sub_prim {
Performance Info: Calling .to_string() (especially on &str) allocates a new String. If done repeatedly in loops, consider alternatives like working with &str or using crates like `itoa`/`ryu` for number-to-string conversion.
info performance to-string-in-loop
PrimitiveValue::Null => "null".to_string(),
Performance Info: Calling .to_string() (especially on &str) allocates a new String. If done repeatedly in loops, consider alternatives like working with &str or using crates like `itoa`/`ryu` for number-to-string conversion.
info performance to-string-in-loop
PrimitiveValue::Boolean(b) => b.to_string(),
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 chars.next() {
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
BinaryOperator::Subtract => match (lhs, rhs) {
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
BinaryOperator::Multiply => match (lhs, rhs) {
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
BinaryOperator::Divide => match (lhs, rhs) {
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
BinaryOperator::Modulo => match (lhs, rhs) {
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
BinaryOperator::Exponent => match (lhs, rhs) {
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
BinaryOperator::BitwiseOr => match (lhs, rhs) {
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
BinaryOperator::BitwiseAnd => match (lhs, rhs) {
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
BinaryOperator::BitwiseXor => match (lhs, rhs) {
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
BinaryOperator::ShiftLeft => match (lhs, rhs) {
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
BinaryOperator::ShiftRight => match (lhs, rhs) {
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
BinaryOperator::UnsignedShiftRight => match (lhs, rhs) {
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
BinaryOperator::LessThan => match (lhs, rhs) {
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
BinaryOperator::LessEqual => match (lhs, rhs) {
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
BinaryOperator::GreaterThan => match (lhs, rhs) {
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
BinaryOperator::GreaterEqual => match (lhs, rhs) {
Info: This standard library function returns a Result. Ensure the Result is handled properly (e.g., using '?', match, if let) rather than potentially panicking with .unwrap() or .expect().
info correctness unhandled-result
trimmed.parse::<f64>().unwrap_or(f64::NAN)

Get this view in your editor

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