compiler/scripts/debug-print-hir.mjs 1,194 lines View on github.com → Search inside
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}

Code quality findings 80

Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (loc == null || typeof loc === "symbol") {
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
if (loc == null || typeof loc === "symbol") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (type == null) return "Type";
Ensure all cases are handled or a default case is present
info correctness switch-without-default
switch (type.kind) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
return type.shapeId != null ? `Object<${type.shapeId}>` : "Object";
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
type.shapeId != null ? `Function<${type.shapeId}>` : "Function";
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
return ret !== "Type" ? `${base}():${ret}` : base;
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (name == null) return "null";
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (typeof name === "object" && name.value != null) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (typeof name === "object" && name.value != null) {
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
if (typeof name === "object" && name.value != null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (range == null) return "[0:0]";
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (scope == null) return "null";
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (id == null) return "null";
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
return `[${pattern.items.map((item) => (item.kind === "Hole" ? "<hole>" : item.kind === "Spread" ? `...$${item.place.identifier.id}` : `$${item.identifier.id}`)).join(", ")}]`;
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
return `{${pattern.properties.map((p) => p.kind === "Spread" ? `...$${p.place.identifier.id}` : `${printObjectPropertyKey(p.key)}: $${p.place.identifier.id}`).join(", ")}}`;
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (ps.kind === "Identifier") return `$${ps.identifier.id}`;
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (ps.kind === "Spread") return `...$${ps.place.identifier.id}`;
Ensure all cases are handled or a default case is present
info correctness switch-without-default
switch (kind) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
`${indent(d + 1)}value: ${value.value === undefined ? "undefined" : JSON.stringify(value.value)}`
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (value.properties != null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (prop.kind === "ObjectProperty") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
`${indent(d + 1)}elements: [${value.elements.map((e) => (e.kind === "Hole" ? "<hole>" : e.kind === "Spread" ? `...$${e.place.identifier.id}` : `$${e.identifier.id}`)).join(", ")}]`
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (b.module != null) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (b.imported != null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (value.tag.kind === "Identifier") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (attr.kind === "JsxAttribute") {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (value.children != null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
kind === "FunctionExpression" ? "FunctionExpression" : "ObjectMethod";
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (kind === "FunctionExpression") {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
`${indent(d + 1)}name: ${value.name != null ? JSON.stringify(value.name) : "null"}`
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
`${indent(d + 1)}aliasingEffects: ${ae != null ? `[${ae.length} effects]` : "null"}`
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
lines.push(`${indent(d + 1)}deps: ${value.deps != null ? `[${value.deps.length} deps]` : "null"}`);
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
lines.push(`${indent(d + 1)}pruned: ${value.pruned === true}`);
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
`${indent(d + 1)}type: ${value.node != null ? value.node.type : "unknown"}`
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (instr.effects != null) {
Ensure all cases are handled or a default case is present
info correctness switch-without-default
switch (kind) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
`${indent(d + 1)}fallthrough: ${terminal.fallthrough != null ? `bb${terminal.fallthrough}` : "null"}`
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (terminal.effects != null) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (c.test != null) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
`${indent(d + 1)}fallthrough: ${terminal.fallthrough != null ? `bb${terminal.fallthrough}` : "null"}`
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
`${indent(d + 1)}loop: ${terminal.loop != null ? `bb${terminal.loop}` : "null"}`
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
`${indent(d + 1)}fallthrough: ${terminal.fallthrough != null ? `bb${terminal.fallthrough}` : "null"}`
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
`${indent(d + 1)}update: ${terminal.update != null ? `bb${terminal.update}` : "null"}`
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
`${indent(d + 1)}fallthrough: ${terminal.fallthrough != null ? `bb${terminal.fallthrough}` : "null"}`
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
`${indent(d + 1)}handler: ${terminal.handler != null ? `bb${terminal.handler}` : "null"}`
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (terminal.effects != null) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (terminal.handlerBinding != null) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
`${indent(d + 1)}fallthrough: ${terminal.fallthrough != null ? `bb${terminal.fallthrough}` : "null"}`
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
`${indent(d1)}id: ${fn.id != null ? JSON.stringify(fn.id) : "null"}`
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (param.kind === "Identifier") {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (fn.returnTypeAnnotation != null) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (fn.aliasingEffects != null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
instr.value.kind === "FunctionExpression" ||
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
instr.value.kind === "ObjectMethod"
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (param.kind === "Identifier") {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (place != null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (value == null) return;
Ensure all cases are handled or a default case is present
info correctness switch-without-default
switch (value.kind) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (arg.kind === "Identifier") collectIdentifiersFromPlace(arg, map);
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
else if (arg.kind === "Spread")
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (arg.kind === "Identifier") collectIdentifiersFromPlace(arg, map);
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
else if (arg.kind === "Spread")
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (value.properties != null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (prop.kind === "ObjectProperty") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (prop.key.kind === "computed")
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (el.kind === "Identifier") collectIdentifiersFromPlace(el, map);
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
else if (el.kind === "Spread")
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (value.tag.kind === "Identifier")
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (attr.kind === "JsxAttribute")
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (value.children != null) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (value.deps != null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (dep.root.kind === "NamedLocal") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (item.kind === "Identifier") collectIdentifiersFromPlace(item, map);
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
else if (item.kind === "Spread")
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (prop.kind === "ObjectProperty") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (prop.key.kind === "computed")
Ensure all cases are handled or a default case is present
info correctness switch-without-default
switch (terminal.kind) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (c.test != null) collectIdentifiersFromPlace(c.test, map);
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (terminal.handlerBinding != null)

Get this view in your editor

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