Use strict equality (===) to prevent type coercion bugs
if (loc == null || typeof loc === "symbol") {
1/**2 * Copyright (c) Meta Platforms, Inc. and affiliates.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 */78/**9 * Debug HIR printer for the Rust port testing infrastructure.10 *11 * Custom printer that walks the HIRFunction structure and prints every field12 * of every identifier, instruction, terminal, and block. Also includes13 * outlined functions (from FunctionExpression instruction values).14 *15 * This does NOT delegate to printFunctionWithOutlined() — it is a standalone16 * walker that produces a detailed, deterministic representation suitable for17 * cross-compiler comparison between the TS and Rust implementations.18 *19 * @param {Function} _printFunctionWithOutlined - Unused (kept for API compat)20 * @param {object} hirFunction - The HIRFunction to print21 * @returns {string} The debug representation22 */23export function debugPrintHIR(_printFunctionWithOutlined, hirFunction) {24 const outlined = [];25 const result = printHIRFunction(hirFunction, 0, outlined);26 const parts = [result];27 for (let i = 0; i < outlined.length; i++) {28 parts.push(printHIRFunction(outlined[i], i + 1, outlined));29 }30 return parts.join("\n\n");31}3233// ---------------------------------------------------------------------------34// Helpers35// ---------------------------------------------------------------------------3637function indent(depth) {38 return " ".repeat(depth);39}4041function formatLoc(loc) {42 if (loc == null || typeof loc === "symbol") {43 return "generated";44 }45 return `${loc.start.line}:${loc.start.column}-${loc.end.line}:${loc.end.column}`;46}4748function formatEffect(effect) {49 // Effect enum values in the TS compiler are lowercase strings like50 // "read", "mutate", "<unknown>", etc.51 return String(effect);52}5354function formatType(type) {55 if (type == null) return "Type";56 switch (type.kind) {57 case "Type":58 return "Type";59 case "Primitive":60 return "Primitive";61 case "Object":62 return type.shapeId != null ? `Object<${type.shapeId}>` : "Object";63 case "Function": {64 const ret = formatType(type.return);65 const base =66 type.shapeId != null ? `Function<${type.shapeId}>` : "Function";67 return ret !== "Type" ? `${base}():${ret}` : base;68 }69 case "Poly":70 return "Poly";71 case "Phi": {72 const ops = type.operands.map(formatType).join(", ");73 return `Phi(${ops})`;74 }75 case "Property": {76 const objType = formatType(type.objectType);77 return `Property(${objType}.${type.objectName})`;78 }79 case "ObjectMethod":80 return "ObjectMethod";81 default:82 return "Type";83 }84}8586function formatIdentifierName(name) {87 if (name == null) return "null";88 if (typeof name === "object" && name.value != null) {89 return JSON.stringify(name.value);90 }91 return JSON.stringify(String(name));92}9394function formatMutableRange(range) {95 if (range == null) return "[0:0]";96 return `[${range.start}:${range.end}]`;97}9899function formatScopeId(scope) {100 if (scope == null) return "null";101 return `@${scope.id}`;102}103104function formatDeclarationId(id) {105 if (id == null) return "null";106 return String(id);107}108109// ---------------------------------------------------------------------------110// Place printing111// ---------------------------------------------------------------------------112113function printPlaceInline(place, depth) {114 const id = place.identifier;115 return [116 `${indent(depth)}Place {`,117 `${indent(depth + 1)}identifier: $${id.id}`,118 `${indent(depth + 1)}effect: ${formatEffect(place.effect)}`,119 `${indent(depth + 1)}reactive: ${place.reactive}`,120 `${indent(depth + 1)}loc: ${formatLoc(place.loc)}`,121 `${indent(depth)}}`,122 ].join("\n");123}124125// ---------------------------------------------------------------------------126// Identifier printing127// ---------------------------------------------------------------------------128129function printIdentifierEntry(identifier, depth) {130 return [131 `${indent(depth)}$${identifier.id}: Identifier {`,132 `${indent(depth + 1)}id: ${identifier.id}`,133 `${indent(depth + 1)}declarationId: ${formatDeclarationId(identifier.declarationId)}`,134 `${indent(depth + 1)}name: ${formatIdentifierName(identifier.name)}`,135 `${indent(depth + 1)}mutableRange: ${formatMutableRange(identifier.mutableRange)}`,136 `${indent(depth + 1)}scope: ${formatScopeId(identifier.scope)}`,137 `${indent(depth + 1)}type: ${formatType(identifier.type)}`,138 `${indent(depth + 1)}loc: ${formatLoc(identifier.loc)}`,139 `${indent(depth)}}`,140 ].join("\n");141}142143// ---------------------------------------------------------------------------144// InstructionValue printing145// ---------------------------------------------------------------------------146147function printObjectPropertyKey(key) {148 switch (key.kind) {149 case "identifier":150 return key.name;151 case "string":152 return `"${key.name}"`;153 case "computed":154 return `[$${key.name.identifier.id}]`;155 case "number":156 return String(key.name);157 default:158 return String(key.name ?? key.kind);159 }160}161162function printPattern(pattern) {163 switch (pattern.kind) {164 case "ArrayPattern":165 return `[${pattern.items.map((item) => (item.kind === "Hole" ? "<hole>" : item.kind === "Spread" ? `...$${item.place.identifier.id}` : `$${item.identifier.id}`)).join(", ")}]`;166 case "ObjectPattern":167 return `{${pattern.properties.map((p) => p.kind === "Spread" ? `...$${p.place.identifier.id}` : `${printObjectPropertyKey(p.key)}: $${p.place.identifier.id}`).join(", ")}}`;168 default:169 return String(pattern);170 }171}172173function printPlaceOrSpread(ps) {174 if (ps.kind === "Identifier") return `$${ps.identifier.id}`;175 if (ps.kind === "Spread") return `...$${ps.place.identifier.id}`;176 return "<hole>";177}178179function printInstructionValueFields(value, depth) {180 const d = depth;181 const lines = [];182 const kind = value.kind;183184 switch (kind) {185 case "LoadLocal":186 lines.push(`${indent(d)}LoadLocal {`);187 lines.push(`${indent(d + 1)}place: $${value.place.identifier.id}`);188 lines.push(`${indent(d)}}`);189 break;190 case "LoadContext":191 lines.push(`${indent(d)}LoadContext {`);192 lines.push(`${indent(d + 1)}place: $${value.place.identifier.id}`);193 lines.push(`${indent(d)}}`);194 break;195 case "DeclareLocal":196 lines.push(`${indent(d)}DeclareLocal {`);197 lines.push(`${indent(d + 1)}lvalue.kind: ${value.lvalue.kind}`);198 lines.push(199 `${indent(d + 1)}lvalue.place: $${value.lvalue.place.identifier.id}`200 );201 lines.push(`${indent(d)}}`);202 break;203 case "DeclareContext":204 lines.push(`${indent(d)}DeclareContext {`);205 lines.push(`${indent(d + 1)}lvalue.kind: ${value.lvalue.kind}`);206 lines.push(207 `${indent(d + 1)}lvalue.place: $${value.lvalue.place.identifier.id}`208 );209 lines.push(`${indent(d)}}`);210 break;211 case "StoreLocal":212 lines.push(`${indent(d)}StoreLocal {`);213 lines.push(`${indent(d + 1)}lvalue.kind: ${value.lvalue.kind}`);214 lines.push(215 `${indent(d + 1)}lvalue.place: $${value.lvalue.place.identifier.id}`216 );217 lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`);218 lines.push(`${indent(d)}}`);219 break;220 case "StoreContext":221 lines.push(`${indent(d)}StoreContext {`);222 lines.push(`${indent(d + 1)}lvalue.kind: ${value.lvalue.kind}`);223 lines.push(224 `${indent(d + 1)}lvalue.place: $${value.lvalue.place.identifier.id}`225 );226 lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`);227 lines.push(`${indent(d)}}`);228 break;229 case "Destructure":230 lines.push(`${indent(d)}Destructure {`);231 lines.push(`${indent(d + 1)}lvalue.kind: ${value.lvalue.kind}`);232 lines.push(233 `${indent(d + 1)}lvalue.pattern: ${printPattern(value.lvalue.pattern)}`234 );235 lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`);236 lines.push(`${indent(d)}}`);237 break;238 case "Primitive":239 lines.push(`${indent(d)}Primitive {`);240 lines.push(241 `${indent(d + 1)}value: ${value.value === undefined ? "undefined" : JSON.stringify(value.value)}`242 );243 lines.push(`${indent(d)}}`);244 break;245 case "JSXText":246 lines.push(`${indent(d)}JSXText {`);247 lines.push(`${indent(d + 1)}value: ${JSON.stringify(value.value)}`);248 lines.push(`${indent(d)}}`);249 break;250 case "BinaryExpression":251 lines.push(`${indent(d)}BinaryExpression {`);252 lines.push(`${indent(d + 1)}operator: ${value.operator}`);253 lines.push(`${indent(d + 1)}left: $${value.left.identifier.id}`);254 lines.push(`${indent(d + 1)}right: $${value.right.identifier.id}`);255 lines.push(`${indent(d)}}`);256 break;257 case "UnaryExpression":258 lines.push(`${indent(d)}UnaryExpression {`);259 lines.push(`${indent(d + 1)}operator: ${value.operator}`);260 lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`);261 lines.push(`${indent(d)}}`);262 break;263 case "CallExpression":264 lines.push(`${indent(d)}CallExpression {`);265 lines.push(`${indent(d + 1)}callee: $${value.callee.identifier.id}`);266 lines.push(267 `${indent(d + 1)}args: [${value.args.map(printPlaceOrSpread).join(", ")}]`268 );269 lines.push(`${indent(d)}}`);270 break;271 case "MethodCall":272 lines.push(`${indent(d)}MethodCall {`);273 lines.push(274 `${indent(d + 1)}receiver: $${value.receiver.identifier.id}`275 );276 lines.push(277 `${indent(d + 1)}property: $${value.property.identifier.id}`278 );279 lines.push(280 `${indent(d + 1)}args: [${value.args.map(printPlaceOrSpread).join(", ")}]`281 );282 lines.push(`${indent(d)}}`);283 break;284 case "NewExpression":285 lines.push(`${indent(d)}NewExpression {`);286 lines.push(`${indent(d + 1)}callee: $${value.callee.identifier.id}`);287 lines.push(288 `${indent(d + 1)}args: [${value.args.map(printPlaceOrSpread).join(", ")}]`289 );290 lines.push(`${indent(d)}}`);291 break;292 case "ObjectExpression":293 lines.push(`${indent(d)}ObjectExpression {`);294 if (value.properties != null) {295 lines.push(`${indent(d + 1)}properties:`);296 for (const prop of value.properties) {297 if (prop.kind === "ObjectProperty") {298 lines.push(299 `${indent(d + 2)}${printObjectPropertyKey(prop.key)}: $${prop.place.identifier.id}`300 );301 } else {302 lines.push(`${indent(d + 2)}...$${prop.place.identifier.id}`);303 }304 }305 } else {306 lines.push(`${indent(d + 1)}properties: null`);307 }308 lines.push(`${indent(d)}}`);309 break;310 case "ArrayExpression":311 lines.push(`${indent(d)}ArrayExpression {`);312 lines.push(313 `${indent(d + 1)}elements: [${value.elements.map((e) => (e.kind === "Hole" ? "<hole>" : e.kind === "Spread" ? `...$${e.place.identifier.id}` : `$${e.identifier.id}`)).join(", ")}]`314 );315 lines.push(`${indent(d)}}`);316 break;317 case "PropertyLoad":318 lines.push(`${indent(d)}PropertyLoad {`);319 lines.push(`${indent(d + 1)}object: $${value.object.identifier.id}`);320 lines.push(`${indent(d + 1)}property: ${value.property}`);321 lines.push(`${indent(d)}}`);322 break;323 case "PropertyStore":324 lines.push(`${indent(d)}PropertyStore {`);325 lines.push(`${indent(d + 1)}object: $${value.object.identifier.id}`);326 lines.push(`${indent(d + 1)}property: ${value.property}`);327 lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`);328 lines.push(`${indent(d)}}`);329 break;330 case "PropertyDelete":331 lines.push(`${indent(d)}PropertyDelete {`);332 lines.push(`${indent(d + 1)}object: $${value.object.identifier.id}`);333 lines.push(`${indent(d + 1)}property: ${value.property}`);334 lines.push(`${indent(d)}}`);335 break;336 case "ComputedLoad":337 lines.push(`${indent(d)}ComputedLoad {`);338 lines.push(`${indent(d + 1)}object: $${value.object.identifier.id}`);339 lines.push(340 `${indent(d + 1)}property: $${value.property.identifier.id}`341 );342 lines.push(`${indent(d)}}`);343 break;344 case "ComputedStore":345 lines.push(`${indent(d)}ComputedStore {`);346 lines.push(`${indent(d + 1)}object: $${value.object.identifier.id}`);347 lines.push(348 `${indent(d + 1)}property: $${value.property.identifier.id}`349 );350 lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`);351 lines.push(`${indent(d)}}`);352 break;353 case "ComputedDelete":354 lines.push(`${indent(d)}ComputedDelete {`);355 lines.push(`${indent(d + 1)}object: $${value.object.identifier.id}`);356 lines.push(357 `${indent(d + 1)}property: $${value.property.identifier.id}`358 );359 lines.push(`${indent(d)}}`);360 break;361 case "LoadGlobal": {362 lines.push(`${indent(d)}LoadGlobal {`);363 const b = value.binding;364 lines.push(`${indent(d + 1)}binding.kind: ${b.kind}`);365 lines.push(`${indent(d + 1)}binding.name: ${b.name}`);366 if (b.module != null) {367 lines.push(`${indent(d + 1)}binding.module: ${b.module}`);368 }369 if (b.imported != null) {370 lines.push(`${indent(d + 1)}binding.imported: ${b.imported}`);371 }372 lines.push(`${indent(d)}}`);373 break;374 }375 case "StoreGlobal":376 lines.push(`${indent(d)}StoreGlobal {`);377 lines.push(`${indent(d + 1)}name: ${value.name}`);378 lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`);379 lines.push(`${indent(d)}}`);380 break;381 case "TypeCastExpression":382 lines.push(`${indent(d)}TypeCastExpression {`);383 lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`);384 lines.push(`${indent(d + 1)}type: ${formatType(value.type)}`);385 lines.push(`${indent(d)}}`);386 break;387 case "JsxExpression": {388 lines.push(`${indent(d)}JsxExpression {`);389 if (value.tag.kind === "Identifier") {390 lines.push(`${indent(d + 1)}tag: $${value.tag.identifier.id}`);391 } else {392 lines.push(`${indent(d + 1)}tag: "${value.tag.name}"`);393 }394 lines.push(`${indent(d + 1)}props:`);395 for (const attr of value.props) {396 if (attr.kind === "JsxAttribute") {397 lines.push(398 `${indent(d + 2)}${attr.name}: $${attr.place.identifier.id}`399 );400 } else {401 lines.push(402 `${indent(d + 2)}...$${attr.argument.identifier.id}`403 );404 }405 }406 if (value.children != null) {407 lines.push(408 `${indent(d + 1)}children: [${value.children.map((c) => `$${c.identifier.id}`).join(", ")}]`409 );410 } else {411 lines.push(`${indent(d + 1)}children: null`);412 }413 lines.push(`${indent(d)}}`);414 break;415 }416 case "JsxFragment":417 lines.push(`${indent(d)}JsxFragment {`);418 lines.push(419 `${indent(d + 1)}children: [${value.children.map((c) => `$${c.identifier.id}`).join(", ")}]`420 );421 lines.push(`${indent(d)}}`);422 break;423 case "FunctionExpression":424 case "ObjectMethod": {425 const label =426 kind === "FunctionExpression" ? "FunctionExpression" : "ObjectMethod";427 lines.push(`${indent(d)}${label} {`);428 if (kind === "FunctionExpression") {429 lines.push(430 `${indent(d + 1)}name: ${value.name != null ? JSON.stringify(value.name) : "null"}`431 );432 }433 lines.push(434 `${indent(d + 1)}loweredFunc.id: ${value.loweredFunc.func.id ?? "null"}`435 );436 // context437 const ctx = value.loweredFunc.func.context;438 lines.push(439 `${indent(d + 1)}context: [${ctx.map((c) => `$${c.identifier.id}`).join(", ")}]`440 );441 // aliasing effects442 const ae = value.loweredFunc.func.aliasingEffects;443 lines.push(444 `${indent(d + 1)}aliasingEffects: ${ae != null ? `[${ae.length} effects]` : "null"}`445 );446 lines.push(`${indent(d)}}`);447 break;448 }449 case "TaggedTemplateExpression":450 lines.push(`${indent(d)}TaggedTemplateExpression {`);451 lines.push(`${indent(d + 1)}tag: $${value.tag.identifier.id}`);452 lines.push(`${indent(d + 1)}value.raw: ${JSON.stringify(value.value.raw)}`);453 lines.push(`${indent(d)}}`);454 break;455 case "TemplateLiteral":456 lines.push(`${indent(d)}TemplateLiteral {`);457 lines.push(458 `${indent(d + 1)}quasis: [${value.quasis.map((q) => JSON.stringify(q.raw)).join(", ")}]`459 );460 lines.push(461 `${indent(d + 1)}subexprs: [${value.subexprs.map((s) => `$${s.identifier.id}`).join(", ")}]`462 );463 lines.push(`${indent(d)}}`);464 break;465 case "RegExpLiteral":466 lines.push(`${indent(d)}RegExpLiteral {`);467 lines.push(`${indent(d + 1)}pattern: ${value.pattern}`);468 lines.push(`${indent(d + 1)}flags: ${value.flags}`);469 lines.push(`${indent(d)}}`);470 break;471 case "MetaProperty":472 lines.push(`${indent(d)}MetaProperty {`);473 lines.push(`${indent(d + 1)}meta: ${value.meta}`);474 lines.push(`${indent(d + 1)}property: ${value.property}`);475 lines.push(`${indent(d)}}`);476 break;477 case "Await":478 lines.push(`${indent(d)}Await {`);479 lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`);480 lines.push(`${indent(d)}}`);481 break;482 case "GetIterator":483 lines.push(`${indent(d)}GetIterator {`);484 lines.push(485 `${indent(d + 1)}collection: $${value.collection.identifier.id}`486 );487 lines.push(`${indent(d)}}`);488 break;489 case "IteratorNext":490 lines.push(`${indent(d)}IteratorNext {`);491 lines.push(492 `${indent(d + 1)}iterator: $${value.iterator.identifier.id}`493 );494 lines.push(495 `${indent(d + 1)}collection: $${value.collection.identifier.id}`496 );497 lines.push(`${indent(d)}}`);498 break;499 case "NextPropertyOf":500 lines.push(`${indent(d)}NextPropertyOf {`);501 lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`);502 lines.push(`${indent(d)}}`);503 break;504 case "PostfixUpdate":505 lines.push(`${indent(d)}PostfixUpdate {`);506 lines.push(`${indent(d + 1)}lvalue: $${value.lvalue.identifier.id}`);507 lines.push(`${indent(d + 1)}operation: ${value.operation}`);508 lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`);509 lines.push(`${indent(d)}}`);510 break;511 case "PrefixUpdate":512 lines.push(`${indent(d)}PrefixUpdate {`);513 lines.push(`${indent(d + 1)}lvalue: $${value.lvalue.identifier.id}`);514 lines.push(`${indent(d + 1)}operation: ${value.operation}`);515 lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`);516 lines.push(`${indent(d)}}`);517 break;518 case "Debugger":519 lines.push(`${indent(d)}Debugger {}`);520 break;521 case "StartMemoize":522 lines.push(`${indent(d)}StartMemoize {`);523 lines.push(`${indent(d + 1)}manualMemoId: ${value.manualMemoId}`);524 lines.push(`${indent(d + 1)}deps: ${value.deps != null ? `[${value.deps.length} deps]` : "null"}`);525 lines.push(`${indent(d)}}`);526 break;527 case "FinishMemoize":528 lines.push(`${indent(d)}FinishMemoize {`);529 lines.push(`${indent(d + 1)}manualMemoId: ${value.manualMemoId}`);530 lines.push(`${indent(d + 1)}decl: $${value.decl.identifier.id}`);531 lines.push(`${indent(d + 1)}pruned: ${value.pruned === true}`);532 lines.push(`${indent(d)}}`);533 break;534 case "UnsupportedNode":535 lines.push(`${indent(d)}UnsupportedNode {`);536 lines.push(537 `${indent(d + 1)}type: ${value.node != null ? value.node.type : "unknown"}`538 );539 lines.push(`${indent(d)}}`);540 break;541 // Reactive-only value types that may appear:542 case "LogicalExpression":543 lines.push(`${indent(d)}LogicalExpression {`);544 lines.push(`${indent(d + 1)}operator: ${value.operator}`);545 lines.push(`${indent(d)}}`);546 break;547 case "ConditionalExpression":548 lines.push(`${indent(d)}ConditionalExpression {}`);549 break;550 case "SequenceExpression":551 lines.push(`${indent(d)}SequenceExpression {}`);552 break;553 case "OptionalExpression":554 lines.push(`${indent(d)}OptionalExpression {`);555 lines.push(`${indent(d + 1)}optional: ${value.optional}`);556 lines.push(`${indent(d)}}`);557 break;558 default:559 lines.push(`${indent(d)}${kind} {}`);560 break;561 }562 return lines.join("\n");563}564565// ---------------------------------------------------------------------------566// Instruction printing567// ---------------------------------------------------------------------------568569function printInstruction(instr, depth) {570 const lines = [];571 lines.push(`${indent(depth)}[${instr.id}] Instruction {`);572 const d = depth + 1;573 lines.push(`${indent(d)}id: ${instr.id}`);574 // lvalue575 lines.push(`${indent(d)}lvalue:`);576 lines.push(printPlaceInline(instr.lvalue, d + 1));577 // value578 lines.push(`${indent(d)}value:`);579 lines.push(printInstructionValueFields(instr.value, d + 1));580 // effects581 if (instr.effects != null) {582 lines.push(`${indent(d)}effects: [${instr.effects.length} effects]`);583 } else {584 lines.push(`${indent(d)}effects: null`);585 }586 lines.push(`${indent(d)}loc: ${formatLoc(instr.loc)}`);587 lines.push(`${indent(depth)}}`);588 return lines.join("\n");589}590591// ---------------------------------------------------------------------------592// Terminal printing593// ---------------------------------------------------------------------------594595function printTerminal(terminal, depth) {596 const lines = [];597 const d = depth;598 const kind = terminal.kind;599 lines.push(`${indent(d)}${terminalName(kind)} {`);600 lines.push(`${indent(d + 1)}id: ${terminal.id}`);601602 switch (kind) {603 case "if":604 lines.push(`${indent(d + 1)}test:`);605 lines.push(printPlaceInline(terminal.test, d + 2));606 lines.push(`${indent(d + 1)}consequent: bb${terminal.consequent}`);607 lines.push(`${indent(d + 1)}alternate: bb${terminal.alternate}`);608 lines.push(609 `${indent(d + 1)}fallthrough: ${terminal.fallthrough != null ? `bb${terminal.fallthrough}` : "null"}`610 );611 break;612 case "branch":613 lines.push(`${indent(d + 1)}test:`);614 lines.push(printPlaceInline(terminal.test, d + 2));615 lines.push(`${indent(d + 1)}consequent: bb${terminal.consequent}`);616 lines.push(`${indent(d + 1)}alternate: bb${terminal.alternate}`);617 lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`);618 break;619 case "return":620 lines.push(`${indent(d + 1)}returnVariant: ${terminal.returnVariant}`);621 lines.push(`${indent(d + 1)}value:`);622 lines.push(printPlaceInline(terminal.value, d + 2));623 if (terminal.effects != null) {624 lines.push(625 `${indent(d + 1)}effects: [${terminal.effects.length} effects]`626 );627 } else {628 lines.push(`${indent(d + 1)}effects: null`);629 }630 break;631 case "throw":632 lines.push(`${indent(d + 1)}value:`);633 lines.push(printPlaceInline(terminal.value, d + 2));634 break;635 case "goto":636 lines.push(`${indent(d + 1)}block: bb${terminal.block}`);637 lines.push(`${indent(d + 1)}variant: ${terminal.variant}`);638 break;639 case "switch":640 lines.push(`${indent(d + 1)}test:`);641 lines.push(printPlaceInline(terminal.test, d + 2));642 lines.push(`${indent(d + 1)}cases:`);643 for (const c of terminal.cases) {644 if (c.test != null) {645 lines.push(`${indent(d + 2)}case $${c.test.identifier.id}: bb${c.block}`);646 } else {647 lines.push(`${indent(d + 2)}default: bb${c.block}`);648 }649 }650 lines.push(651 `${indent(d + 1)}fallthrough: ${terminal.fallthrough != null ? `bb${terminal.fallthrough}` : "null"}`652 );653 break;654 case "do-while":655 lines.push(`${indent(d + 1)}loop: bb${terminal.loop}`);656 lines.push(`${indent(d + 1)}test: bb${terminal.test}`);657 lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`);658 break;659 case "while":660 lines.push(`${indent(d + 1)}test: bb${terminal.test}`);661 lines.push(662 `${indent(d + 1)}loop: ${terminal.loop != null ? `bb${terminal.loop}` : "null"}`663 );664 lines.push(665 `${indent(d + 1)}fallthrough: ${terminal.fallthrough != null ? `bb${terminal.fallthrough}` : "null"}`666 );667 break;668 case "for":669 lines.push(`${indent(d + 1)}init: bb${terminal.init}`);670 lines.push(`${indent(d + 1)}test: bb${terminal.test}`);671 lines.push(672 `${indent(d + 1)}update: ${terminal.update != null ? `bb${terminal.update}` : "null"}`673 );674 lines.push(`${indent(d + 1)}loop: bb${terminal.loop}`);675 lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`);676 break;677 case "for-of":678 lines.push(`${indent(d + 1)}init: bb${terminal.init}`);679 lines.push(`${indent(d + 1)}test: bb${terminal.test}`);680 lines.push(`${indent(d + 1)}loop: bb${terminal.loop}`);681 lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`);682 break;683 case "for-in":684 lines.push(`${indent(d + 1)}init: bb${terminal.init}`);685 lines.push(`${indent(d + 1)}loop: bb${terminal.loop}`);686 lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`);687 break;688 case "logical":689 lines.push(`${indent(d + 1)}operator: ${terminal.operator}`);690 lines.push(`${indent(d + 1)}test: bb${terminal.test}`);691 lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`);692 break;693 case "ternary":694 lines.push(`${indent(d + 1)}test: bb${terminal.test}`);695 lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`);696 break;697 case "optional":698 lines.push(`${indent(d + 1)}optional: ${terminal.optional}`);699 lines.push(`${indent(d + 1)}test: bb${terminal.test}`);700 lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`);701 break;702 case "label":703 lines.push(`${indent(d + 1)}block: bb${terminal.block}`);704 lines.push(705 `${indent(d + 1)}fallthrough: ${terminal.fallthrough != null ? `bb${terminal.fallthrough}` : "null"}`706 );707 break;708 case "sequence":709 lines.push(`${indent(d + 1)}block: bb${terminal.block}`);710 lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`);711 break;712 case "maybe-throw":713 lines.push(`${indent(d + 1)}continuation: bb${terminal.continuation}`);714 lines.push(715 `${indent(d + 1)}handler: ${terminal.handler != null ? `bb${terminal.handler}` : "null"}`716 );717 if (terminal.effects != null) {718 lines.push(719 `${indent(d + 1)}effects: [${terminal.effects.length} effects]`720 );721 } else {722 lines.push(`${indent(d + 1)}effects: null`);723 }724 break;725 case "try":726 lines.push(`${indent(d + 1)}block: bb${terminal.block}`);727 if (terminal.handlerBinding != null) {728 lines.push(`${indent(d + 1)}handlerBinding:`);729 lines.push(printPlaceInline(terminal.handlerBinding, d + 2));730 } else {731 lines.push(`${indent(d + 1)}handlerBinding: null`);732 }733 lines.push(`${indent(d + 1)}handler: bb${terminal.handler}`);734 lines.push(735 `${indent(d + 1)}fallthrough: ${terminal.fallthrough != null ? `bb${terminal.fallthrough}` : "null"}`736 );737 break;738 case "scope":739 lines.push(`${indent(d + 1)}scope: @${terminal.scope.id}`);740 lines.push(`${indent(d + 1)}block: bb${terminal.block}`);741 lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`);742 break;743 case "pruned-scope":744 lines.push(`${indent(d + 1)}scope: @${terminal.scope.id}`);745 lines.push(`${indent(d + 1)}block: bb${terminal.block}`);746 lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`);747 break;748 case "unreachable":749 break;750 case "unsupported":751 break;752 default:753 break;754 }755756 lines.push(`${indent(d + 1)}loc: ${formatLoc(terminal.loc)}`);757 lines.push(`${indent(d)}}`);758 return lines.join("\n");759}760761function terminalName(kind) {762 const names = {763 if: "If",764 branch: "Branch",765 return: "Return",766 throw: "Throw",767 goto: "Goto",768 switch: "Switch",769 "do-while": "DoWhile",770 while: "While",771 for: "For",772 "for-of": "ForOf",773 "for-in": "ForIn",774 logical: "Logical",775 ternary: "Ternary",776 optional: "Optional",777 label: "Label",778 sequence: "Sequence",779 "maybe-throw": "MaybeThrow",780 try: "Try",781 scope: "Scope",782 "pruned-scope": "PrunedScope",783 unreachable: "Unreachable",784 unsupported: "Unsupported",785 };786 return names[kind] ?? kind;787}788789// ---------------------------------------------------------------------------790// Phi printing791// ---------------------------------------------------------------------------792793function printPhi(phi, depth) {794 const lines = [];795 lines.push(`${indent(depth)}Phi {`);796 lines.push(`${indent(depth + 1)}place: $${phi.place.identifier.id}`);797 lines.push(`${indent(depth + 1)}operands:`);798 // phi.operands is a Map<BlockId, Place>799 const sortedOperands = [...phi.operands].sort((a, b) => a[0] - b[0]);800 for (const [blockId, place] of sortedOperands) {801 lines.push(802 `${indent(depth + 2)}bb${blockId}: $${place.identifier.id}`803 );804 }805 lines.push(`${indent(depth)}}`);806 return lines.join("\n");807}808809// ---------------------------------------------------------------------------810// Main function printer811// ---------------------------------------------------------------------------812813function printHIRFunction(fn, functionIndex, outlinedCollector) {814 const lines = [];815 const d0 = 0;816 const d1 = 1;817 const d2 = 2;818819 lines.push(`${indent(d0)}Function #${functionIndex}:`);820821 // id822 lines.push(823 `${indent(d1)}id: ${fn.id != null ? JSON.stringify(fn.id) : "null"}`824 );825826 // params827 lines.push(`${indent(d1)}params:`);828 for (let i = 0; i < fn.params.length; i++) {829 const param = fn.params[i];830 if (param.kind === "Identifier") {831 lines.push(`${indent(d2)}[${i}]`);832 lines.push(printPlaceInline(param, d2 + 1));833 } else {834 // Spread835 lines.push(`${indent(d2)}[${i}] ...`);836 lines.push(printPlaceInline(param.place, d2 + 1));837 }838 }839840 // returns841 lines.push(`${indent(d1)}returns:`);842 lines.push(printPlaceInline(fn.returns, d2));843844 // returnTypeAnnotation845 if (fn.returnTypeAnnotation != null) {846 lines.push(`${indent(d1)}returnTypeAnnotation: ${JSON.stringify(fn.returnTypeAnnotation)}`);847 } else {848 lines.push(`${indent(d1)}returnTypeAnnotation: null`);849 }850851 // context852 if (fn.context.length > 0) {853 lines.push(`${indent(d1)}context:`);854 for (const ctx of fn.context) {855 lines.push(printPlaceInline(ctx, d2));856 }857 } else {858 lines.push(`${indent(d1)}context: []`);859 }860861 // directives862 if (fn.directives.length > 0) {863 lines.push(864 `${indent(d1)}directives: [${fn.directives.map((d) => JSON.stringify(d)).join(", ")}]`865 );866 } else {867 lines.push(`${indent(d1)}directives: []`);868 }869870 // generator / async871 lines.push(`${indent(d1)}generator: ${fn.generator}`);872 lines.push(`${indent(d1)}async: ${fn.async}`);873874 // aliasingEffects875 if (fn.aliasingEffects != null) {876 lines.push(877 `${indent(d1)}aliasingEffects: [${fn.aliasingEffects.length} effects]`878 );879 } else {880 lines.push(`${indent(d1)}aliasingEffects: null`);881 }882883 // Collect all identifiers from the function884 const identifiers = new Map();885 collectIdentifiers(fn, identifiers);886887 lines.push("");888 lines.push(`${indent(d1)}Identifiers:`);889 const sortedIds = [...identifiers.entries()].sort((a, b) => a[0] - b[0]);890 for (const [, identifier] of sortedIds) {891 lines.push(printIdentifierEntry(identifier, d2));892 }893894 // Blocks (in order from body.blocks, which is RPO)895 lines.push("");896 lines.push(`${indent(d1)}Blocks:`);897 for (const [blockId, block] of fn.body.blocks) {898 lines.push(`${indent(d2)}bb${blockId} (${block.kind}):`);899 const d3 = d2 + 1;900901 // preds902 const preds = [...block.preds].sort((a, b) => a - b);903 lines.push(`${indent(d3)}preds: [${preds.map((p) => `bb${p}`).join(", ")}]`);904905 // phis906 if (block.phis.size > 0) {907 lines.push(`${indent(d3)}phis:`);908 for (const phi of block.phis) {909 lines.push(printPhi(phi, d3 + 1));910 }911 } else {912 lines.push(`${indent(d3)}phis: []`);913 }914915 // instructions916 lines.push(`${indent(d3)}instructions:`);917 for (const instr of block.instructions) {918 lines.push(printInstruction(instr, d3 + 1));919 // Collect outlined functions920 if (921 instr.value.kind === "FunctionExpression" ||922 instr.value.kind === "ObjectMethod"923 ) {924 outlinedCollector.push(instr.value.loweredFunc.func);925 }926 }927928 // terminal929 lines.push(`${indent(d3)}terminal:`);930 lines.push(printTerminal(block.terminal, d3 + 1));931 }932933 return lines.join("\n");934}935936// ---------------------------------------------------------------------------937// Identifier collection938// ---------------------------------------------------------------------------939940function collectIdentifiers(fn, map) {941 // From params942 for (const param of fn.params) {943 if (param.kind === "Identifier") {944 addIdentifier(map, param.identifier);945 } else {946 addIdentifier(map, param.place.identifier);947 }948 }949950 // returns951 addIdentifier(map, fn.returns.identifier);952953 // context954 for (const ctx of fn.context) {955 addIdentifier(map, ctx.identifier);956 }957958 // From blocks959 for (const [, block] of fn.body.blocks) {960 // phis961 for (const phi of block.phis) {962 addIdentifier(map, phi.place.identifier);963 for (const [, place] of phi.operands) {964 addIdentifier(map, place.identifier);965 }966 }967968 // instructions969 for (const instr of block.instructions) {970 addIdentifier(map, instr.lvalue.identifier);971 collectIdentifiersFromValue(instr.value, map);972 }973974 // terminal975 collectIdentifiersFromTerminal(block.terminal, map);976 }977}978979function addIdentifier(map, identifier) {980 if (!map.has(identifier.id)) {981 map.set(identifier.id, identifier);982 }983}984985function collectIdentifiersFromPlace(place, map) {986 if (place != null) {987 addIdentifier(map, place.identifier);988 }989}990991function collectIdentifiersFromValue(value, map) {992 if (value == null) return;993 switch (value.kind) {994 case "LoadLocal":995 case "LoadContext":996 collectIdentifiersFromPlace(value.place, map);997 break;998 case "DeclareLocal":999 case "DeclareContext":1000 collectIdentifiersFromPlace(value.lvalue.place, map);1001 break;1002 case "StoreLocal":1003 case "StoreContext":1004 collectIdentifiersFromPlace(value.lvalue.place, map);1005 collectIdentifiersFromPlace(value.value, map);1006 break;1007 case "Destructure":1008 collectIdentifiersFromPattern(value.lvalue.pattern, map);1009 collectIdentifiersFromPlace(value.value, map);1010 break;1011 case "BinaryExpression":1012 collectIdentifiersFromPlace(value.left, map);1013 collectIdentifiersFromPlace(value.right, map);1014 break;1015 case "UnaryExpression":1016 collectIdentifiersFromPlace(value.value, map);1017 break;1018 case "CallExpression":1019 case "NewExpression":1020 collectIdentifiersFromPlace(value.callee, map);1021 for (const arg of value.args) {1022 if (arg.kind === "Identifier") collectIdentifiersFromPlace(arg, map);1023 else if (arg.kind === "Spread")1024 collectIdentifiersFromPlace(arg.place, map);1025 }1026 break;1027 case "MethodCall":1028 collectIdentifiersFromPlace(value.receiver, map);1029 collectIdentifiersFromPlace(value.property, map);1030 for (const arg of value.args) {1031 if (arg.kind === "Identifier") collectIdentifiersFromPlace(arg, map);1032 else if (arg.kind === "Spread")1033 collectIdentifiersFromPlace(arg.place, map);1034 }1035 break;1036 case "ObjectExpression":1037 if (value.properties != null) {1038 for (const prop of value.properties) {1039 if (prop.kind === "ObjectProperty") {1040 collectIdentifiersFromPlace(prop.place, map);1041 if (prop.key.kind === "computed")1042 collectIdentifiersFromPlace(prop.key.name, map);1043 } else {1044 collectIdentifiersFromPlace(prop.place, map);1045 }1046 }1047 }1048 break;1049 case "ArrayExpression":1050 for (const el of value.elements) {1051 if (el.kind === "Identifier") collectIdentifiersFromPlace(el, map);1052 else if (el.kind === "Spread")1053 collectIdentifiersFromPlace(el.place, map);1054 }1055 break;1056 case "PropertyLoad":1057 case "PropertyDelete":1058 collectIdentifiersFromPlace(value.object, map);1059 break;1060 case "PropertyStore":1061 collectIdentifiersFromPlace(value.object, map);1062 collectIdentifiersFromPlace(value.value, map);1063 break;1064 case "ComputedLoad":1065 case "ComputedDelete":1066 collectIdentifiersFromPlace(value.object, map);1067 collectIdentifiersFromPlace(value.property, map);1068 break;1069 case "ComputedStore":1070 collectIdentifiersFromPlace(value.object, map);1071 collectIdentifiersFromPlace(value.property, map);1072 collectIdentifiersFromPlace(value.value, map);1073 break;1074 case "StoreGlobal":1075 collectIdentifiersFromPlace(value.value, map);1076 break;1077 case "TypeCastExpression":1078 collectIdentifiersFromPlace(value.value, map);1079 break;1080 case "JsxExpression":1081 if (value.tag.kind === "Identifier")1082 collectIdentifiersFromPlace(value.tag, map);1083 for (const attr of value.props) {1084 if (attr.kind === "JsxAttribute")1085 collectIdentifiersFromPlace(attr.place, map);1086 else collectIdentifiersFromPlace(attr.argument, map);1087 }1088 if (value.children != null) {1089 for (const child of value.children)1090 collectIdentifiersFromPlace(child, map);1091 }1092 break;1093 case "JsxFragment":1094 for (const child of value.children)1095 collectIdentifiersFromPlace(child, map);1096 break;1097 case "FunctionExpression":1098 case "ObjectMethod":1099 // context of lowered func1100 for (const ctx of value.loweredFunc.func.context) {1101 collectIdentifiersFromPlace(ctx, map);1102 }1103 break;1104 case "TaggedTemplateExpression":1105 collectIdentifiersFromPlace(value.tag, map);1106 break;1107 case "TemplateLiteral":1108 for (const s of value.subexprs) collectIdentifiersFromPlace(s, map);1109 break;1110 case "Await":1111 collectIdentifiersFromPlace(value.value, map);1112 break;1113 case "GetIterator":1114 collectIdentifiersFromPlace(value.collection, map);1115 break;1116 case "IteratorNext":1117 collectIdentifiersFromPlace(value.iterator, map);1118 collectIdentifiersFromPlace(value.collection, map);1119 break;1120 case "NextPropertyOf":1121 collectIdentifiersFromPlace(value.value, map);1122 break;1123 case "PostfixUpdate":1124 case "PrefixUpdate":1125 collectIdentifiersFromPlace(value.lvalue, map);1126 collectIdentifiersFromPlace(value.value, map);1127 break;1128 case "FinishMemoize":1129 collectIdentifiersFromPlace(value.decl, map);1130 break;1131 case "StartMemoize":1132 if (value.deps != null) {1133 for (const dep of value.deps) {1134 if (dep.root.kind === "NamedLocal") {1135 collectIdentifiersFromPlace(dep.root.value, map);1136 }1137 }1138 }1139 break;1140 default:1141 break;1142 }1143}11441145function collectIdentifiersFromPattern(pattern, map) {1146 switch (pattern.kind) {1147 case "ArrayPattern":1148 for (const item of pattern.items) {1149 if (item.kind === "Identifier") collectIdentifiersFromPlace(item, map);1150 else if (item.kind === "Spread")1151 collectIdentifiersFromPlace(item.place, map);1152 }1153 break;1154 case "ObjectPattern":1155 for (const prop of pattern.properties) {1156 if (prop.kind === "ObjectProperty") {1157 collectIdentifiersFromPlace(prop.place, map);1158 if (prop.key.kind === "computed")1159 collectIdentifiersFromPlace(prop.key.name, map);1160 } else {1161 collectIdentifiersFromPlace(prop.place, map);1162 }1163 }1164 break;1165 }1166}11671168function collectIdentifiersFromTerminal(terminal, map) {1169 switch (terminal.kind) {1170 case "if":1171 case "branch":1172 collectIdentifiersFromPlace(terminal.test, map);1173 break;1174 case "return":1175 collectIdentifiersFromPlace(terminal.value, map);1176 break;1177 case "throw":1178 collectIdentifiersFromPlace(terminal.value, map);1179 break;1180 case "switch":1181 collectIdentifiersFromPlace(terminal.test, map);1182 for (const c of terminal.cases) {1183 if (c.test != null) collectIdentifiersFromPlace(c.test, map);1184 }1185 break;1186 case "try":1187 if (terminal.handlerBinding != null)1188 collectIdentifiersFromPlace(terminal.handlerBinding, map);1189 break;1190 default:1191 break;1192 }1193}
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.