@scriptc/compiler 0.0.21 → 0.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +117 -37
  2. package/dist/backend/cc-cache.test.d.ts +1 -0
  3. package/dist/backend/cc-cache.test.js +2507 -0
  4. package/dist/backend/cc-cache.test.js.map +1 -0
  5. package/dist/backend/cc.d.ts +69 -11
  6. package/dist/backend/cc.js +1937 -222
  7. package/dist/backend/cc.js.map +1 -1
  8. package/dist/backend/emission/emit-async.js +3 -1
  9. package/dist/backend/emission/emit-async.js.map +1 -1
  10. package/dist/backend/emission/emit-exprs.d.ts +10 -0
  11. package/dist/backend/emission/emit-exprs.js +482 -18
  12. package/dist/backend/emission/emit-exprs.js.map +1 -1
  13. package/dist/backend/emission/emit-stmts.js +13 -5
  14. package/dist/backend/emission/emit-stmts.js.map +1 -1
  15. package/dist/backend/emission/emit-types.js +4 -1
  16. package/dist/backend/emission/emit-types.js.map +1 -1
  17. package/dist/backend/emission/emit-walkers.js +108 -7
  18. package/dist/backend/emission/emit-walkers.js.map +1 -1
  19. package/dist/backend/emission/emitter.d.ts +27 -1
  20. package/dist/backend/emission/emitter.js +84 -3
  21. package/dist/backend/emission/emitter.js.map +1 -1
  22. package/dist/backend/llvm/dyn.d.ts +1 -0
  23. package/dist/backend/llvm/dyn.js +305 -8
  24. package/dist/backend/llvm/dyn.js.map +1 -1
  25. package/dist/backend/llvm/emitter.js +831 -23
  26. package/dist/backend/llvm/emitter.js.map +1 -1
  27. package/dist/backend/llvm/shapes.js +3 -2
  28. package/dist/backend/llvm/shapes.js.map +1 -1
  29. package/dist/compat/fetch-profile.d.ts +118 -0
  30. package/dist/compat/fetch-profile.js +531 -0
  31. package/dist/compat/fetch-profile.js.map +1 -0
  32. package/dist/coverage/surface-manifest.js +69 -0
  33. package/dist/coverage/surface-manifest.js.map +1 -1
  34. package/dist/diagnostics/diagnostic.d.ts +10 -0
  35. package/dist/diagnostics/diagnostic.js +27 -1
  36. package/dist/diagnostics/diagnostic.js.map +1 -1
  37. package/dist/frontend/lowering/lower-builtins.d.ts +24 -15
  38. package/dist/frontend/lowering/lower-builtins.js +217 -69
  39. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  40. package/dist/frontend/lowering/lower-calls.js +41 -0
  41. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  42. package/dist/frontend/lowering/lower-classes.js +32 -11
  43. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  44. package/dist/frontend/lowering/lower-exprs.d.ts +3 -3
  45. package/dist/frontend/lowering/lower-exprs.js +87 -15
  46. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  47. package/dist/frontend/lowering/lower-generators.js +7 -1
  48. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  49. package/dist/frontend/lowering/lower-island.d.ts +123 -7
  50. package/dist/frontend/lowering/lower-island.js +1976 -26
  51. package/dist/frontend/lowering/lower-island.js.map +1 -1
  52. package/dist/frontend/lowering/lower-modules.js +17 -1
  53. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  54. package/dist/frontend/lowering/lower-stmts.js +33 -9
  55. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  56. package/dist/frontend/lowering/lowerer.d.ts +40 -0
  57. package/dist/frontend/lowering/lowerer.js +290 -18
  58. package/dist/frontend/lowering/lowerer.js.map +1 -1
  59. package/dist/frontend/lowering/surfaces.js +55 -12
  60. package/dist/frontend/lowering/surfaces.js.map +1 -1
  61. package/dist/frontend/program.d.ts +20 -4
  62. package/dist/frontend/program.js +391 -49
  63. package/dist/frontend/program.js.map +1 -1
  64. package/dist/frontend/resolve.d.ts +10 -0
  65. package/dist/frontend/resolve.js +37 -0
  66. package/dist/frontend/resolve.js.map +1 -1
  67. package/dist/frontend/ts7/enums.d.ts +9 -0
  68. package/dist/frontend/ts7/enums.js +8 -6
  69. package/dist/frontend/ts7/enums.js.map +1 -1
  70. package/dist/frontend/ts7/program.js +4 -1
  71. package/dist/frontend/ts7/program.js.map +1 -1
  72. package/dist/frontend/types.d.ts +16 -9
  73. package/dist/frontend/types.js +119 -38
  74. package/dist/frontend/types.js.map +1 -1
  75. package/dist/index.d.ts +7 -1
  76. package/dist/index.js +70 -14
  77. package/dist/index.js.map +1 -1
  78. package/dist/ir/nodes.d.ts +55 -26
  79. package/dist/ir/nodes.js +42 -29
  80. package/dist/ir/nodes.js.map +1 -1
  81. package/dist/ir/validate.js +106 -9
  82. package/dist/ir/validate.js.map +1 -1
  83. package/dist/library/int-infer.js +7 -1
  84. package/dist/library/int-infer.js.map +1 -1
  85. package/dist/library/int-infer.test.js +80 -0
  86. package/dist/library/int-infer.test.js.map +1 -1
  87. package/dist/library/sidecar-validate.js +5 -0
  88. package/dist/library/sidecar-validate.js.map +1 -1
  89. package/dist/library/sidecar.d.ts +3 -0
  90. package/dist/library/sidecar.js.map +1 -1
  91. package/package.json +2 -2
  92. package/surface-manifest.json +1097 -130
@@ -785,6 +785,41 @@ export function lowerBuiltinModuleCall(L, expr, bi, fn, loc) {
785
785
  if (bi.module === "fs" && bi.member === "watch") {
786
786
  return lowerFsWatchCall(L, expr, loc);
787
787
  }
788
+ // fs.readSync(fd, buffer, offset, length[, position]) — normalize the
789
+ // current-offset forms to Node/libuv's -1 sentinel so the IR and native
790
+ // ABI stay fixed-width. A real numeric position is a positioned read
791
+ // and therefore must not advance the descriptor. Literal null is the
792
+ // documented current-offset spelling; richer nullable expressions must
793
+ // narrow first so no effectful evaluation is silently discarded.
794
+ if (bi.module === "fs" && bi.member === "readSync") {
795
+ const supported = "use readSync(fd, buffer, offset, length[, position]) with a numeric position or literal null; options objects and bigint positions have no lowering";
796
+ if ((expr.arguments.length !== 4 && expr.arguments.length !== 5) ||
797
+ expr.arguments.some(ts.isSpreadElement)) {
798
+ L.noLowering(`readSync with ${expr.arguments.length} argument${expr.arguments.length === 1 ? "" : "s"}`, expr, supported);
799
+ }
800
+ const args = [
801
+ L.lowerExprExpecting(expr.arguments[0], F64),
802
+ L.lowerExprExpecting(expr.arguments[1], BYTES_U8),
803
+ L.lowerExprExpecting(expr.arguments[2], F64),
804
+ L.lowerExprExpecting(expr.arguments[3], F64),
805
+ ];
806
+ const positionNode = expr.arguments[4];
807
+ let positionValueNode = positionNode;
808
+ while (positionValueNode && ts.isParenthesizedExpression(positionValueNode)) {
809
+ positionValueNode = positionValueNode.expression;
810
+ }
811
+ if (positionNode === undefined || positionValueNode.kind === ts.SyntaxKind.NullKeyword) {
812
+ args.push({ kind: "numLit", value: -1, type: F64, loc });
813
+ }
814
+ else {
815
+ const positionType = L.mapTypeOf(L.typeOf(positionNode));
816
+ if (positionType?.kind !== "f64") {
817
+ L.noLowering(`readSync with a '${positionType ? L.fmt(positionType) : L.checker.typeToString(L.typeOf(positionNode))}' position`, positionNode, supported);
818
+ }
819
+ args.push(L.lowerExprExpecting(positionNode, F64));
820
+ }
821
+ return { kind: "libCall", fn: "fs.readSync", args, type: F64, loc };
822
+ }
788
823
  if (bi.module === "child_process" &&
789
824
  (bi.member === "execFileSync" || bi.member === "execSync")) {
790
825
  return L.lowerExecSyncCall(expr, bi.member === "execSync", loc);
@@ -5326,13 +5361,29 @@ export function lowerNumberStaticCall(L, call, access) {
5326
5361
  }
5327
5362
  return null; // other Number statics land on the member fence
5328
5363
  }
5329
- /** The Date slice: `Date.now()` and the COMPOSED
5330
- * `new Date(ms?).toISOString()` — the Date object between the two calls
5331
- * never exists (the crypto randomBytes(n).toString(enc) precedent). An
5332
- * omitted constructor argument completes with date.now; a one-argument
5333
- * form takes the milliseconds. String parsing, Y/M/D fields (local-time
5334
- * semantics), and Date VALUES stay fenced — lowerNew carries the hint.
5335
- * Null when this is neither form. */
5364
+ const DATE_GETTER_FNS = {
5365
+ getFullYear: "date.getFullYear",
5366
+ getUTCFullYear: "date.getUTCFullYear",
5367
+ getMonth: "date.getMonth",
5368
+ getUTCMonth: "date.getUTCMonth",
5369
+ getDate: "date.getDate",
5370
+ getUTCDate: "date.getUTCDate",
5371
+ getDay: "date.getDay",
5372
+ getUTCDay: "date.getUTCDay",
5373
+ getHours: "date.getHours",
5374
+ getUTCHours: "date.getUTCHours",
5375
+ getMinutes: "date.getMinutes",
5376
+ getUTCMinutes: "date.getUTCMinutes",
5377
+ getSeconds: "date.getSeconds",
5378
+ getUTCSeconds: "date.getUTCSeconds",
5379
+ getMilliseconds: "date.getMilliseconds",
5380
+ getUTCMilliseconds: "date.getUTCMilliseconds",
5381
+ getTimezoneOffset: "date.getTimezoneOffset",
5382
+ };
5383
+ const DATE_METHOD_HINT = "getTime(), valueOf(), toISOString(), the local/UTC calendar getters, and getTimezoneOffset() are supported; Date setters and locale/string formatters have no lowering";
5384
+ /** The Date slice: statics plus read-only Date values backed by one
5385
+ * TimeClip'd millisecond scalar. Construction lives in lowerNew;
5386
+ * identity and mutating methods remain fenced. */
5336
5387
  export function lowerDateCall(L, call, access) {
5337
5388
  if (call.questionDotToken || access.questionDotToken)
5338
5389
  return null;
@@ -5363,83 +5414,180 @@ export function lowerDateCall(L, call, access) {
5363
5414
  }
5364
5415
  return { kind: "libCall", fn: "date.utc", args, type: F64, loc };
5365
5416
  }
5366
- if (access.name.text !== "toISOString" && access.name.text !== "getTime")
5417
+ if (L.mapTypeOf(L.typeOf(access.expression))?.kind !== "date")
5367
5418
  return null;
5368
- const recv = access.expression;
5369
- if (!ts.isNewExpression(recv) || !ts.isIdentifier(recv.expression))
5370
- return null;
5371
- const sym = L.resolveValueSymbol(recv.expression);
5372
- if (!sym || sym.name !== "Date" || !L.isStdlibSymbol(sym))
5373
- return null;
5374
- if (access.name.text === "getTime") {
5375
- // The composed `new Date(x).getTime()` read — the Date value
5376
- // between the two never materializes (the toISOString precedent).
5377
- // new Date().getTime() IS Date.now(); the STRING form parses the
5378
- // bounded date-string grammar (the X509 validity shape portless's
5379
- // cert-expiry check reads, plus ECMA's own date-time format) and
5380
- // answers NaN elsewhere — a documented divergence from V8's wider
5381
- // parser. The ms form is pointless composition; the fence points at
5382
- // the value.
5383
- if (call.arguments.length !== 0) {
5384
- L.noLowering("getTime with arguments", call);
5385
- }
5386
- const ctorArgs = recv.arguments ?? [];
5387
- if (ctorArgs.length === 0) {
5388
- return { kind: "libCall", fn: "date.now", args: [], type: F64, loc };
5389
- }
5390
- if (ctorArgs.length !== 1) {
5391
- L.noLowering("new Date with year/month/day arguments", recv, "the field constructor is local-time; only new Date() and new Date(dateString) compose with .getTime()");
5392
- }
5393
- const arg = L.lowerExpr(ctorArgs[0]);
5394
- if (arg.type.kind !== "string") {
5395
- L.noLowering(`new Date of '${L.fmt(arg.type)}' values composed with .getTime()`, ctorArgs[0], arg.type.kind === "f64"
5396
- ? "new Date(ms).getTime() is the ms value — use it directly (or Date.now())"
5397
- : "the composed form parses date STRINGS — narrow unions first");
5398
- }
5399
- return { kind: "libCall", fn: "date.parseGetTime", args: [arg], type: F64, loc };
5400
- }
5419
+ if (!L.isStdlibMember(access))
5420
+ return null;
5421
+ const name = access.name.text;
5401
5422
  if (call.arguments.length !== 0) {
5402
- L.noLowering("toISOString with arguments", call);
5423
+ L.noLowering(`Date.prototype.${name} with arguments`, call, DATE_METHOD_HINT);
5403
5424
  }
5404
- const ctorArgs = recv.arguments ?? [];
5405
- let ms;
5406
- if (ctorArgs.length === 0) {
5407
- ms = { kind: "libCall", fn: "date.now", args: [], type: F64, loc };
5425
+ const receiver = L.lowerExpr(access.expression);
5426
+ if (receiver.type.kind !== "date")
5427
+ L.badType(access.expression, L.typeOf(access.expression));
5428
+ if (name === "getTime" || name === "valueOf") {
5429
+ return {
5430
+ kind: "libCall",
5431
+ fn: name === "getTime" ? "date.getTime" : "date.valueOf",
5432
+ args: [receiver],
5433
+ type: F64,
5434
+ loc,
5435
+ };
5408
5436
  }
5409
- else if (ctorArgs.length === 1) {
5410
- const arg = L.lowerExpr(ctorArgs[0]);
5411
- if (arg.type.kind !== "f64") {
5412
- L.noLowering(`new Date of '${L.fmt(arg.type)}' values`, ctorArgs[0], "only the milliseconds form composes — new Date(ms).toISOString(); date-string parsing has no lowering");
5413
- }
5414
- ms = arg;
5437
+ if (name === "toISOString") {
5438
+ return { kind: "libCall", fn: "date.toISOStringValue", args: [receiver], type: STRING, loc };
5415
5439
  }
5416
- else {
5417
- L.noLowering("new Date with year/month/day arguments", recv, "the field constructor is local-time; only new Date() and new Date(ms) compose with .toISOString()");
5440
+ const fn = DATE_GETTER_FNS[name];
5441
+ if (fn !== undefined) {
5442
+ return { kind: "libCall", fn, args: [receiver], type: F64, loc };
5418
5443
  }
5419
- return { kind: "libCall", fn: "date.toISOString", args: [ms], type: STRING, loc };
5444
+ L.noLowering(`Date.prototype.${name}`, call, DATE_METHOD_HINT, L.checker.getSymbolAtLocation(access.name));
5420
5445
  }
5421
- /** The WHATWG encoder pair, COMPOSED: `new TextDecoder().decode(bytes)`
5422
- * and `new TextEncoder().encode(s)` — the encoder object between the two
5423
- * calls never exists (the crypto/Date precedent; bare construction is
5424
- * fenced in lowerNew with the composed hint). decode is the runtime's
5425
- * WHATWG utf-8 decode with the leading BOM stripped; a zero-argument
5426
- * decode() is "" like the spec's. encode IS Buffer.from(s, "utf8") —
5427
- * ScrStr storage is well-formed UTF-8, so the bytes are identical (lone
5446
+ /** A direct construction of THE stdlib TextEncoder/TextDecoder, through
5447
+ * type-only wrappers. Name alone is never enough: a user class with the
5448
+ * same spelling keeps the ordinary class lowering. */
5449
+ function directTextCodecCtorOf(L, expr) {
5450
+ const ctor = stripTypeCasts(expr);
5451
+ if (!ts.isNewExpression(ctor))
5452
+ return null;
5453
+ const callee = stripTypeCasts(ctor.expression);
5454
+ if (!ts.isIdentifier(callee))
5455
+ return null;
5456
+ if (callee.text !== "TextDecoder" && callee.text !== "TextEncoder")
5457
+ return null;
5458
+ const sym = L.resolveValueSymbol(callee);
5459
+ if (!sym || !L.isStdlibSymbol(sym))
5460
+ return null;
5461
+ if (sym.name !== "TextDecoder" && sym.name !== "TextEncoder")
5462
+ return null;
5463
+ return { cls: sym.name, ctor };
5464
+ }
5465
+ /** True when construction itself is effect-free and inside the already
5466
+ * lowered codec slice, so a const binding can be erased and calls can
5467
+ * resolve back to the initializer. TextDecoder's explicit label must be
5468
+ * an actual literal here: accepting an arbitrary expression merely typed
5469
+ * as "utf-8" would move or repeat its effects when the binding is erased. */
5470
+ function erasableTextCodecCtor(info) {
5471
+ const args = info.ctor.arguments ?? [];
5472
+ if (info.cls === "TextEncoder")
5473
+ return args.length === 0;
5474
+ if (args.length === 0)
5475
+ return true;
5476
+ if (args.length !== 1)
5477
+ return false;
5478
+ const label = stripTypeCasts(args[0]);
5479
+ return ts.isStringLiteralLike(label) && (label.text === "utf-8" || label.text === "utf8");
5480
+ }
5481
+ /** `const encoder = new TextEncoder()` / the default TextDecoder twin:
5482
+ * compile-time alias plumbing with no runtime object. Calls through the
5483
+ * stable binding are recognized by textCodecReceiverOf below; any other
5484
+ * reached value use keeps the ordinary SC2020 representation fence. Both
5485
+ * declaration walks call this and independently gate on constness. */
5486
+ export function textCodecBindingClassOf(L, nameNode, init) {
5487
+ if (!ts.isIdentifier(nameNode) || init === undefined)
5488
+ return null;
5489
+ const decl = nameNode.parent;
5490
+ if (!ts.isVariableDeclaration(decl) || !ts.isVariableDeclarationList(decl.parent) ||
5491
+ !ts.isVariableStatement(decl.parent.parent)) {
5492
+ return null;
5493
+ }
5494
+ const info = directTextCodecCtorOf(L, init);
5495
+ return info !== null && erasableTextCodecCtor(info) ? info.cls : null;
5496
+ }
5497
+ export function textCodecBindingDecl(L, nameNode, init) {
5498
+ return textCodecBindingClassOf(L, nameNode, init) !== null;
5499
+ }
5500
+ /** The inline composed receiver, or a const identifier whose initializer
5501
+ * is an erasable codec construction in the same execution scope and
5502
+ * after that declaration. Following the declaration instead of
5503
+ * materializing the value is honest for the supported slice: receiver
5504
+ * reads are pure, construction has no effects, and every non-call use
5505
+ * fences because there is deliberately no general value lowering. */
5506
+ function textCodecReceiverOf(L, expr) {
5507
+ const direct = directTextCodecCtorOf(L, expr);
5508
+ if (direct !== null)
5509
+ return direct;
5510
+ const receiver = stripTypeCasts(expr);
5511
+ if (!ts.isIdentifier(receiver))
5512
+ return null;
5513
+ const sym = L.resolveValueSymbol(receiver);
5514
+ const decl = sym ? L.checker.valueDeclarationOf(sym) : undefined;
5515
+ if (!decl || !ts.isVariableDeclaration(decl) || decl.initializer === undefined ||
5516
+ !ts.isVariableDeclarationList(decl.parent) || (decl.parent.flags & ts.NodeFlags.Const) === 0 ||
5517
+ !textCodecBindingDecl(L, decl.name, decl.initializer)) {
5518
+ return null;
5519
+ }
5520
+ // A closure can run before the const initializes (TDZ), and an
5521
+ // imported binding can be observed during a module cycle; both need
5522
+ // real runtime storage rather than this deliberately trivial rewrite.
5523
+ const executionScope = (node) => {
5524
+ let child = node;
5525
+ for (let cur = node.parent;; child = cur, cur = cur.parent) {
5526
+ if (ts.isFunctionLike(cur) || ts.isSourceFile(cur))
5527
+ return cur;
5528
+ // An instance field initializer runs when an object is constructed,
5529
+ // not when its enclosing class expression evaluates. Treat it like
5530
+ // a closure boundary: a later source position does not prove the
5531
+ // codec declaration ran (a switch can enter a following case and
5532
+ // instantiate the class while the binding is still in its TDZ).
5533
+ if (ts.isPropertyDeclaration(cur) && cur.initializer === child &&
5534
+ (ts.getCombinedModifierFlags(cur) & ts.ModifierFlags.Static) === 0) {
5535
+ return cur;
5536
+ }
5537
+ }
5538
+ };
5539
+ if (executionScope(receiver) !== executionScope(decl) || receiver.getStart() < decl.end)
5540
+ return null;
5541
+ // All switch clauses share one lexical environment, but dispatch can
5542
+ // enter a later clause without executing a const in an earlier one.
5543
+ // TypeScript normally diagnoses the direct read; an @ts-expect-error
5544
+ // can deliberately retain the runtime TDZ shape, so source order alone
5545
+ // is not a sufficient proof. A codec declared in a clause is erasable
5546
+ // only for uses inside that exact clause's subtree (nested switches are
5547
+ // fine; closures and instance initializers already fail executionScope).
5548
+ const switchClauseOf = (node) => {
5549
+ for (let cur = node.parent; cur !== undefined; cur = cur.parent) {
5550
+ if (ts.isCaseClause(cur) || ts.isDefaultClause(cur))
5551
+ return cur;
5552
+ if (ts.isFunctionLike(cur) || ts.isSourceFile(cur))
5553
+ return null;
5554
+ }
5555
+ return null;
5556
+ };
5557
+ const declClause = switchClauseOf(decl);
5558
+ if (declClause !== null) {
5559
+ let insideDeclClause = false;
5560
+ for (let cur = receiver; cur !== undefined; cur = cur.parent) {
5561
+ if (cur === declClause) {
5562
+ insideDeclClause = true;
5563
+ break;
5564
+ }
5565
+ }
5566
+ if (!insideDeclClause)
5567
+ return null;
5568
+ }
5569
+ return directTextCodecCtorOf(L, decl.initializer);
5570
+ }
5571
+ /** The WHATWG encoder pair, COMPOSED or through an erasable const binding:
5572
+ * `new TextDecoder().decode(bytes)`, `new TextEncoder().encode(s)`, and
5573
+ * the idiomatic store-then-call equivalents. The codec object never
5574
+ * exists (the crypto/Date precedent); bare construction and value uses
5575
+ * are fenced with the composed hint. decode is the runtime's WHATWG
5576
+ * utf-8 decode with the leading BOM stripped; a zero-argument decode()
5577
+ * is "" like the spec's. encode IS Buffer.from(s, "utf8") — ScrStr
5578
+ * storage is well-formed UTF-8, so the bytes are identical (lone
5428
5579
  * surrogates became U+FFFD at string construction, exactly what the
5429
- * spec's encoder emits). Null when this is neither composed form. */
5580
+ * spec's encoder emits). Null when this is neither supported form. */
5430
5581
  export function lowerTextCodecCall(L, call, access) {
5431
5582
  if (call.questionDotToken || access.questionDotToken)
5432
5583
  return null;
5433
5584
  const member = access.name.text;
5434
5585
  if (member !== "decode" && member !== "encode")
5435
5586
  return null;
5436
- const recv = access.expression;
5437
- if (!ts.isNewExpression(recv) || !ts.isIdentifier(recv.expression))
5438
- return null;
5439
- const sym = L.resolveValueSymbol(recv.expression);
5440
- const cls = sym?.name;
5441
- if (!sym || !L.isStdlibSymbol(sym))
5587
+ const info = textCodecReceiverOf(L, access.expression);
5588
+ if (info === null || !L.isStdlibMember(access))
5442
5589
  return null;
5590
+ const { cls, ctor: recv } = info;
5443
5591
  if (!(cls === "TextDecoder" && member === "decode") && !(cls === "TextEncoder" && member === "encode")) {
5444
5592
  return null;
5445
5593
  }