compiler/crates/react_compiler/src/debug_print.rs RUST 735 lines View on github.com → Search inside
1use react_compiler_diagnostics::CompilerError;2use react_compiler_hir::environment::Environment;3use react_compiler_hir::print::{self, PrintFormatter};4use react_compiler_hir::{5    BasicBlock, BlockId, HirFunction, Instruction, ParamPattern, Place, Terminal,6};78// =============================================================================9// DebugPrinter struct — thin wrapper around PrintFormatter for HIR-specific logic10// =============================================================================1112struct DebugPrinter<'a> {13    fmt: PrintFormatter<'a>,14}1516impl<'a> DebugPrinter<'a> {17    fn new(env: &'a Environment) -> Self {18        Self {19            fmt: PrintFormatter::new(env),20        }21    }2223    // =========================================================================24    // Function25    // =========================================================================2627    fn format_function(&mut self, func: &HirFunction) {28        self.fmt.indent();29        self.fmt.line(&format!(30            "id: {}",31            match &func.id {32                Some(id) => format!("\"{}\"", id),33                None => "null".to_string(),34            }35        ));36        self.fmt.line(&format!(37            "name_hint: {}",38            match &func.name_hint {39                Some(h) => format!("\"{}\"", h),40                None => "null".to_string(),41            }42        ));43        self.fmt.line(&format!("fn_type: {:?}", func.fn_type));44        self.fmt.line(&format!("generator: {}", func.generator));45        self.fmt.line(&format!("is_async: {}", func.is_async));46        self.fmt47            .line(&format!("loc: {}", print::format_loc(&func.loc)));4849        // params50        self.fmt.line("params:");51        self.fmt.indent();52        for (i, param) in func.params.iter().enumerate() {53            match param {54                ParamPattern::Place(place) => {55                    self.fmt.format_place_field(&format!("[{}]", i), place);56                }57                ParamPattern::Spread(spread) => {58                    self.fmt.line(&format!("[{}] Spread:", i));59                    self.fmt.indent();60                    self.fmt.format_place_field("place", &spread.place);61                    self.fmt.dedent();62                }63            }64        }65        self.fmt.dedent();6667        // returns68        self.fmt.line("returns:");69        self.fmt.indent();70        self.fmt.format_place_field("value", &func.returns);71        self.fmt.dedent();7273        // context74        self.fmt.line("context:");75        self.fmt.indent();76        for (i, place) in func.context.iter().enumerate() {77            self.fmt.format_place_field(&format!("[{}]", i), place);78        }79        self.fmt.dedent();8081        // aliasing_effects82        match &func.aliasing_effects {83            Some(effects) => {84                self.fmt.line("aliasingEffects:");85                self.fmt.indent();86                for (i, eff) in effects.iter().enumerate() {87                    self.fmt88                        .line(&format!("[{}] {}", i, self.fmt.format_effect(eff)));89                }90                self.fmt.dedent();91            }92            None => self.fmt.line("aliasingEffects: null"),93        }9495        // directives96        self.fmt.line("directives:");97        self.fmt.indent();98        for (i, d) in func.directives.iter().enumerate() {99            self.fmt.line(&format!("[{}] \"{}\"", i, d));100        }101        self.fmt.dedent();102103        // return_type_annotation104        self.fmt.line(&format!(105            "returnTypeAnnotation: {}",106            match &func.return_type_annotation {107                Some(ann) => ann.clone(),108                None => "null".to_string(),109            }110        ));111112        self.fmt.line("");113        self.fmt.line("Blocks:");114        self.fmt.indent();115        for (block_id, block) in &func.body.blocks {116            self.format_block(block_id, block, &func.instructions);117        }118        self.fmt.dedent();119        self.fmt.dedent();120    }121122    // =========================================================================123    // Block124    // =========================================================================125126    fn format_block(127        &mut self,128        block_id: &BlockId,129        block: &BasicBlock,130        instructions: &[Instruction],131    ) {132        self.fmt133            .line(&format!("bb{} ({}):", block_id.0, block.kind));134        self.fmt.indent();135136        // preds137        let preds: Vec<String> = block.preds.iter().map(|p| format!("bb{}", p.0)).collect();138        self.fmt.line(&format!("preds: [{}]", preds.join(", ")));139140        // phis141        self.fmt.line("phis:");142        self.fmt.indent();143        for phi in &block.phis {144            self.format_phi(phi);145        }146        self.fmt.dedent();147148        // instructions149        self.fmt.line("instructions:");150        self.fmt.indent();151        for (index, instr_id) in block.instructions.iter().enumerate() {152            let instr = &instructions[instr_id.0 as usize];153            self.format_instruction(instr, index);154        }155        self.fmt.dedent();156157        // terminal158        self.fmt.line("terminal:");159        self.fmt.indent();160        self.format_terminal(&block.terminal);161        self.fmt.dedent();162163        self.fmt.dedent();164    }165166    // =========================================================================167    // Phi168    // =========================================================================169170    fn format_phi(&mut self, phi: &react_compiler_hir::Phi) {171        self.fmt.line("Phi {");172        self.fmt.indent();173        self.fmt.format_place_field("place", &phi.place);174        self.fmt.line("operands:");175        self.fmt.indent();176        for (block_id, place) in &phi.operands {177            self.fmt.line(&format!("bb{}:", block_id.0));178            self.fmt.indent();179            self.fmt.format_place_field("value", place);180            self.fmt.dedent();181        }182        self.fmt.dedent();183        self.fmt.dedent();184        self.fmt.line("}");185    }186187    // =========================================================================188    // Instruction189    // =========================================================================190191    fn format_instruction(&mut self, instr: &Instruction, index: usize) {192        self.fmt.line(&format!("[{}] Instruction {{", index));193        self.fmt.indent();194        self.fmt.line(&format!("id: {}", instr.id.0));195        self.fmt.format_place_field("lvalue", &instr.lvalue);196        self.fmt.line("value:");197        self.fmt.indent();198        // For the HIR printer, inner functions are formatted via format_function199        self.fmt.format_instruction_value(200            &instr.value,201            Some(&|fmt: &mut PrintFormatter, func: &HirFunction| {202                // We need to recursively format the inner function203                // Use a temporary DebugPrinter that shares the formatter state204                let mut inner = DebugPrinter {205                    fmt: PrintFormatter {206                        env: fmt.env,207                        seen_identifiers: std::mem::take(&mut fmt.seen_identifiers),208                        seen_scopes: std::mem::take(&mut fmt.seen_scopes),209                        output: Vec::new(),210                        indent_level: fmt.indent_level,211                    },212                };213                inner.format_function(func);214                // Write the output lines into the parent formatter215                for line in &inner.fmt.output {216                    fmt.line_raw(line);217                }218                // Copy back the seen state219                fmt.seen_identifiers = inner.fmt.seen_identifiers;220                fmt.seen_scopes = inner.fmt.seen_scopes;221            }),222        );223        self.fmt.dedent();224        match &instr.effects {225            Some(effects) => {226                self.fmt.line("effects:");227                self.fmt.indent();228                for (i, eff) in effects.iter().enumerate() {229                    self.fmt230                        .line(&format!("[{}] {}", i, self.fmt.format_effect(eff)));231                }232                self.fmt.dedent();233            }234            None => self.fmt.line("effects: null"),235        }236        self.fmt237            .line(&format!("loc: {}", print::format_loc(&instr.loc)));238        self.fmt.dedent();239        self.fmt.line("}");240    }241242    // =========================================================================243    // Terminal244    // =========================================================================245246    fn format_terminal(&mut self, terminal: &Terminal) {247        match terminal {248            Terminal::If {249                test,250                consequent,251                alternate,252                fallthrough,253                id,254                loc,255            } => {256                self.fmt.line("If {");257                self.fmt.indent();258                self.fmt.line(&format!("id: {}", id.0));259                self.fmt.format_place_field("test", test);260                self.fmt.line(&format!("consequent: bb{}", consequent.0));261                self.fmt.line(&format!("alternate: bb{}", alternate.0));262                self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));263                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));264                self.fmt.dedent();265                self.fmt.line("}");266            }267            Terminal::Branch {268                test,269                consequent,270                alternate,271                fallthrough,272                id,273                loc,274            } => {275                self.fmt.line("Branch {");276                self.fmt.indent();277                self.fmt.line(&format!("id: {}", id.0));278                self.fmt.format_place_field("test", test);279                self.fmt.line(&format!("consequent: bb{}", consequent.0));280                self.fmt.line(&format!("alternate: bb{}", alternate.0));281                self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));282                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));283                self.fmt.dedent();284                self.fmt.line("}");285            }286            Terminal::Logical {287                operator,288                test,289                fallthrough,290                id,291                loc,292            } => {293                self.fmt.line("Logical {");294                self.fmt.indent();295                self.fmt.line(&format!("id: {}", id.0));296                self.fmt.line(&format!("operator: \"{}\"", operator));297                self.fmt.line(&format!("test: bb{}", test.0));298                self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));299                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));300                self.fmt.dedent();301                self.fmt.line("}");302            }303            Terminal::Ternary {304                test,305                fallthrough,306                id,307                loc,308            } => {309                self.fmt.line("Ternary {");310                self.fmt.indent();311                self.fmt.line(&format!("id: {}", id.0));312                self.fmt.line(&format!("test: bb{}", test.0));313                self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));314                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));315                self.fmt.dedent();316                self.fmt.line("}");317            }318            Terminal::Optional {319                optional,320                test,321                fallthrough,322                id,323                loc,324            } => {325                self.fmt.line("Optional {");326                self.fmt.indent();327                self.fmt.line(&format!("id: {}", id.0));328                self.fmt.line(&format!("optional: {}", optional));329                self.fmt.line(&format!("test: bb{}", test.0));330                self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));331                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));332                self.fmt.dedent();333                self.fmt.line("}");334            }335            Terminal::Throw { value, id, loc } => {336                self.fmt.line("Throw {");337                self.fmt.indent();338                self.fmt.line(&format!("id: {}", id.0));339                self.fmt.format_place_field("value", value);340                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));341                self.fmt.dedent();342                self.fmt.line("}");343            }344            Terminal::Return {345                value,346                return_variant,347                id,348                loc,349                effects,350            } => {351                self.fmt.line("Return {");352                self.fmt.indent();353                self.fmt.line(&format!("id: {}", id.0));354                self.fmt355                    .line(&format!("returnVariant: {:?}", return_variant));356                self.fmt.format_place_field("value", value);357                match effects {358                    Some(e) => {359                        self.fmt.line("effects:");360                        self.fmt.indent();361                        for (i, eff) in e.iter().enumerate() {362                            self.fmt363                                .line(&format!("[{}] {}", i, self.fmt.format_effect(eff)));364                        }365                        self.fmt.dedent();366                    }367                    None => self.fmt.line("effects: null"),368                }369                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));370                self.fmt.dedent();371                self.fmt.line("}");372            }373            Terminal::Goto {374                block,375                variant,376                id,377                loc,378            } => {379                self.fmt.line("Goto {");380                self.fmt.indent();381                self.fmt.line(&format!("id: {}", id.0));382                self.fmt.line(&format!("block: bb{}", block.0));383                self.fmt.line(&format!("variant: {:?}", variant));384                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));385                self.fmt.dedent();386                self.fmt.line("}");387            }388            Terminal::Switch {389                test,390                cases,391                fallthrough,392                id,393                loc,394            } => {395                self.fmt.line("Switch {");396                self.fmt.indent();397                self.fmt.line(&format!("id: {}", id.0));398                self.fmt.format_place_field("test", test);399                self.fmt.line("cases:");400                self.fmt.indent();401                for (i, case) in cases.iter().enumerate() {402                    match &case.test {403                        Some(p) => {404                            self.fmt.line(&format!("[{}] Case {{", i));405                            self.fmt.indent();406                            self.fmt.format_place_field("test", p);407                            self.fmt.line(&format!("block: bb{}", case.block.0));408                            self.fmt.dedent();409                            self.fmt.line("}");410                        }411                        None => {412                            self.fmt413                                .line(&format!("[{}] Default {{ block: bb{} }}", i, case.block.0));414                        }415                    }416                }417                self.fmt.dedent();418                self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));419                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));420                self.fmt.dedent();421                self.fmt.line("}");422            }423            Terminal::DoWhile {424                loop_block,425                test,426                fallthrough,427                id,428                loc,429            } => {430                self.fmt.line("DoWhile {");431                self.fmt.indent();432                self.fmt.line(&format!("id: {}", id.0));433                self.fmt.line(&format!("loop: bb{}", loop_block.0));434                self.fmt.line(&format!("test: bb{}", test.0));435                self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));436                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));437                self.fmt.dedent();438                self.fmt.line("}");439            }440            Terminal::While {441                test,442                loop_block,443                fallthrough,444                id,445                loc,446            } => {447                self.fmt.line("While {");448                self.fmt.indent();449                self.fmt.line(&format!("id: {}", id.0));450                self.fmt.line(&format!("test: bb{}", test.0));451                self.fmt.line(&format!("loop: bb{}", loop_block.0));452                self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));453                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));454                self.fmt.dedent();455                self.fmt.line("}");456            }457            Terminal::For {458                init,459                test,460                update,461                loop_block,462                fallthrough,463                id,464                loc,465            } => {466                self.fmt.line("For {");467                self.fmt.indent();468                self.fmt.line(&format!("id: {}", id.0));469                self.fmt.line(&format!("init: bb{}", init.0));470                self.fmt.line(&format!("test: bb{}", test.0));471                self.fmt.line(&format!(472                    "update: {}",473                    match update {474                        Some(u) => format!("bb{}", u.0),475                        None => "null".to_string(),476                    }477                ));478                self.fmt.line(&format!("loop: bb{}", loop_block.0));479                self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));480                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));481                self.fmt.dedent();482                self.fmt.line("}");483            }484            Terminal::ForOf {485                init,486                test,487                loop_block,488                fallthrough,489                id,490                loc,491            } => {492                self.fmt.line("ForOf {");493                self.fmt.indent();494                self.fmt.line(&format!("id: {}", id.0));495                self.fmt.line(&format!("init: bb{}", init.0));496                self.fmt.line(&format!("test: bb{}", test.0));497                self.fmt.line(&format!("loop: bb{}", loop_block.0));498                self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));499                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));500                self.fmt.dedent();501                self.fmt.line("}");502            }503            Terminal::ForIn {504                init,505                loop_block,506                fallthrough,507                id,508                loc,509            } => {510                self.fmt.line("ForIn {");511                self.fmt.indent();512                self.fmt.line(&format!("id: {}", id.0));513                self.fmt.line(&format!("init: bb{}", init.0));514                self.fmt.line(&format!("loop: bb{}", loop_block.0));515                self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));516                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));517                self.fmt.dedent();518                self.fmt.line("}");519            }520            Terminal::Label {521                block,522                fallthrough,523                id,524                loc,525            } => {526                self.fmt.line("Label {");527                self.fmt.indent();528                self.fmt.line(&format!("id: {}", id.0));529                self.fmt.line(&format!("block: bb{}", block.0));530                self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));531                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));532                self.fmt.dedent();533                self.fmt.line("}");534            }535            Terminal::Sequence {536                block,537                fallthrough,538                id,539                loc,540            } => {541                self.fmt.line("Sequence {");542                self.fmt.indent();543                self.fmt.line(&format!("id: {}", id.0));544                self.fmt.line(&format!("block: bb{}", block.0));545                self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));546                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));547                self.fmt.dedent();548                self.fmt.line("}");549            }550            Terminal::Unreachable { id, loc } => {551                self.fmt.line(&format!(552                    "Unreachable {{ id: {}, loc: {} }}",553                    id.0,554                    print::format_loc(loc)555                ));556            }557            Terminal::Unsupported { id, loc } => {558                self.fmt.line(&format!(559                    "Unsupported {{ id: {}, loc: {} }}",560                    id.0,561                    print::format_loc(loc)562                ));563            }564            Terminal::MaybeThrow {565                continuation,566                handler,567                id,568                loc,569                effects,570            } => {571                self.fmt.line("MaybeThrow {");572                self.fmt.indent();573                self.fmt.line(&format!("id: {}", id.0));574                self.fmt575                    .line(&format!("continuation: bb{}", continuation.0));576                self.fmt.line(&format!(577                    "handler: {}",578                    match handler {579                        Some(h) => format!("bb{}", h.0),580                        None => "null".to_string(),581                    }582                ));583                match effects {584                    Some(e) => {585                        self.fmt.line("effects:");586                        self.fmt.indent();587                        for (i, eff) in e.iter().enumerate() {588                            self.fmt589                                .line(&format!("[{}] {}", i, self.fmt.format_effect(eff)));590                        }591                        self.fmt.dedent();592                    }593                    None => self.fmt.line("effects: null"),594                }595                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));596                self.fmt.dedent();597                self.fmt.line("}");598            }599            Terminal::Scope {600                fallthrough,601                block,602                scope,603                id,604                loc,605            } => {606                self.fmt.line("Scope {");607                self.fmt.indent();608                self.fmt.line(&format!("id: {}", id.0));609                self.fmt.format_scope_field("scope", *scope);610                self.fmt.line(&format!("block: bb{}", block.0));611                self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));612                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));613                self.fmt.dedent();614                self.fmt.line("}");615            }616            Terminal::PrunedScope {617                fallthrough,618                block,619                scope,620                id,621                loc,622            } => {623                self.fmt.line("PrunedScope {");624                self.fmt.indent();625                self.fmt.line(&format!("id: {}", id.0));626                self.fmt.format_scope_field("scope", *scope);627                self.fmt.line(&format!("block: bb{}", block.0));628                self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));629                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));630                self.fmt.dedent();631                self.fmt.line("}");632            }633            Terminal::Try {634                block,635                handler_binding,636                handler,637                fallthrough,638                id,639                loc,640            } => {641                self.fmt.line("Try {");642                self.fmt.indent();643                self.fmt.line(&format!("id: {}", id.0));644                self.fmt.line(&format!("block: bb{}", block.0));645                self.fmt.line(&format!("handler: bb{}", handler.0));646                match handler_binding {647                    Some(p) => self.fmt.format_place_field("handlerBinding", p),648                    None => self.fmt.line("handlerBinding: null"),649                }650                self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));651                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));652                self.fmt.dedent();653                self.fmt.line("}");654            }655        }656    }657}658659// =============================================================================660// Entry point661// =============================================================================662663pub fn debug_hir(hir: &HirFunction, env: &Environment) -> String {664    let mut printer = DebugPrinter::new(env);665    printer.format_function(hir);666667    // Print outlined functions (matches TS DebugPrintHIR.ts: printDebugHIR)668    for outlined in env.get_outlined_functions() {669        printer.fmt.line("");670        printer.format_function(&outlined.func);671    }672673    printer.fmt.line("");674    printer.fmt.line("Environment:");675    printer.fmt.indent();676    printer.fmt.format_errors(&env.errors);677    printer.fmt.dedent();678679    printer.fmt.to_string_output()680}681682// =============================================================================683// Error formatting (kept for backward compatibility)684// =============================================================================685686pub fn format_errors(error: &CompilerError) -> String {687    let env = Environment::new();688    let mut fmt = PrintFormatter::new(&env);689    fmt.format_errors(error);690    fmt.to_string_output()691}692693/// Format an HIR function into a reactive PrintFormatter.694/// This bridges the two debug printers so inner functions in FunctionExpression/ObjectMethod695/// can be printed within the reactive function output.696pub fn format_hir_function_into(reactive_fmt: &mut PrintFormatter, func: &HirFunction) {697    // Create a temporary DebugPrinter that shares the same environment698    let mut printer = DebugPrinter {699        fmt: PrintFormatter {700            env: reactive_fmt.env,701            seen_identifiers: std::mem::take(&mut reactive_fmt.seen_identifiers),702            seen_scopes: std::mem::take(&mut reactive_fmt.seen_scopes),703            output: Vec::new(),704            indent_level: reactive_fmt.indent_level,705        },706    };707    printer.format_function(func);708709    // Write the output lines into the reactive formatter710    for line in &printer.fmt.output {711        reactive_fmt.line_raw(line);712    }713    // Copy back the seen state714    reactive_fmt.seen_identifiers = printer.fmt.seen_identifiers;715    reactive_fmt.seen_scopes = printer.fmt.seen_scopes;716}717718// =============================================================================719// Helpers for effect formatting (kept for backward compatibility)720// =============================================================================721722#[allow(dead_code)]723fn format_place_short(place: &Place, env: &Environment) -> String {724    let ident = &env.identifiers[place.identifier.0 as usize];725    let name = match &ident.name {726        Some(name) => name.value().to_string(),727        None => String::new(),728    };729    let scope = match ident.scope {730        Some(scope_id) => format!(":{}", scope_id.0),731        None => String::new(),732    };733    format!("{}${}{}", name, place.identifier.0, scope)734}

Code quality findings 6

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 = &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];
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(ann) => ann.clone(),
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
None => "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
None => "null".to_string(),
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)]

Get this view in your editor

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