@scriptc/compiler 0.0.32 → 0.0.34

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 (120) hide show
  1. package/dist/backend/cc-cache.test.js +430 -1
  2. package/dist/backend/cc-cache.test.js.map +1 -1
  3. package/dist/backend/cc.d.ts +25 -0
  4. package/dist/backend/cc.js +818 -88
  5. package/dist/backend/cc.js.map +1 -1
  6. package/dist/backend/emission/emit-exprs.js +79 -3
  7. package/dist/backend/emission/emit-exprs.js.map +1 -1
  8. package/dist/backend/emission/emit-shapes.js +37 -4
  9. package/dist/backend/emission/emit-shapes.js.map +1 -1
  10. package/dist/backend/emission/emitter.d.ts +23 -7
  11. package/dist/backend/emission/emitter.js +171 -27
  12. package/dist/backend/emission/emitter.js.map +1 -1
  13. package/dist/backend/emission/may-throw.js +7 -4
  14. package/dist/backend/emission/may-throw.js.map +1 -1
  15. package/dist/backend/ffi-callbacks.d.ts +38 -1
  16. package/dist/backend/ffi-callbacks.js +76 -3
  17. package/dist/backend/ffi-callbacks.js.map +1 -1
  18. package/dist/backend/library-identity.d.ts +22 -0
  19. package/dist/backend/library-identity.js +103 -0
  20. package/dist/backend/library-identity.js.map +1 -0
  21. package/dist/backend/llvm/emitter.d.ts +3 -0
  22. package/dist/backend/llvm/emitter.js +278 -17
  23. package/dist/backend/llvm/emitter.js.map +1 -1
  24. package/dist/backend/llvm/shapes.d.ts +1 -0
  25. package/dist/backend/llvm/shapes.js +25 -1
  26. package/dist/backend/llvm/shapes.js.map +1 -1
  27. package/dist/backend/mangle.d.ts +1 -0
  28. package/dist/backend/mangle.js +3 -0
  29. package/dist/backend/mangle.js.map +1 -1
  30. package/dist/backend/object-localize.d.ts +5 -5
  31. package/dist/backend/object-localize.js +19 -16
  32. package/dist/backend/object-localize.js.map +1 -1
  33. package/dist/backend/object-localize.test.js +37 -13
  34. package/dist/backend/object-localize.test.js.map +1 -1
  35. package/dist/diagnostics/diagnostic.js +2 -0
  36. package/dist/diagnostics/diagnostic.js.map +1 -1
  37. package/dist/ffi/profile.d.ts +17 -5
  38. package/dist/ffi/profile.js +169 -22
  39. package/dist/ffi/profile.js.map +1 -1
  40. package/dist/frontend/input-tracker.d.ts +82 -0
  41. package/dist/frontend/input-tracker.js +380 -0
  42. package/dist/frontend/input-tracker.js.map +1 -0
  43. package/dist/frontend/input-tracker.test.d.ts +1 -0
  44. package/dist/frontend/input-tracker.test.js +137 -0
  45. package/dist/frontend/input-tracker.test.js.map +1 -0
  46. package/dist/frontend/lowering/lower-builtins.js +2 -8
  47. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  48. package/dist/frontend/lowering/lower-calls.d.ts +1 -0
  49. package/dist/frontend/lowering/lower-calls.js +244 -163
  50. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  51. package/dist/frontend/lowering/lower-classes.js +3 -0
  52. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  53. package/dist/frontend/lowering/lower-containers.js +113 -28
  54. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  55. package/dist/frontend/lowering/lower-exprs.js +67 -1
  56. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  57. package/dist/frontend/lowering/lower-inspect.js +45 -26
  58. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  59. package/dist/frontend/lowering/lower-modules.js +1 -1
  60. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  61. package/dist/frontend/lowering/lower-stmts.js +48 -3
  62. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  63. package/dist/frontend/lowering/lowerer.d.ts +79 -29
  64. package/dist/frontend/lowering/lowerer.js +429 -87
  65. package/dist/frontend/lowering/lowerer.js.map +1 -1
  66. package/dist/frontend/npm-static-rewrite.js +25 -26
  67. package/dist/frontend/npm-static-rewrite.js.map +1 -1
  68. package/dist/frontend/npm-static.js +29 -30
  69. package/dist/frontend/npm-static.js.map +1 -1
  70. package/dist/frontend/npm-static.test.d.ts +1 -0
  71. package/dist/frontend/npm-static.test.js +15 -0
  72. package/dist/frontend/npm-static.test.js.map +1 -0
  73. package/dist/frontend/npm.js +5 -17
  74. package/dist/frontend/npm.js.map +1 -1
  75. package/dist/frontend/program.js +2 -6
  76. package/dist/frontend/program.js.map +1 -1
  77. package/dist/frontend/resolve.js +8 -29
  78. package/dist/frontend/resolve.js.map +1 -1
  79. package/dist/frontend/ts7/checker.d.ts +2 -0
  80. package/dist/frontend/ts7/checker.js +20 -3
  81. package/dist/frontend/ts7/checker.js.map +1 -1
  82. package/dist/frontend/ts7/program.js +17 -18
  83. package/dist/frontend/ts7/program.js.map +1 -1
  84. package/dist/frontend/types.d.ts +41 -0
  85. package/dist/frontend/types.js +147 -8
  86. package/dist/frontend/types.js.map +1 -1
  87. package/dist/index.d.ts +1 -1
  88. package/dist/index.js +275 -41
  89. package/dist/index.js.map +1 -1
  90. package/dist/ir/nodes.d.ts +42 -12
  91. package/dist/ir/nodes.js +7 -1
  92. package/dist/ir/nodes.js.map +1 -1
  93. package/dist/ir/serialize.d.ts +1 -1
  94. package/dist/ir/serialize.js +1 -1
  95. package/dist/ir/validate.js +104 -1
  96. package/dist/ir/validate.js.map +1 -1
  97. package/dist/library/early-cache.d.ts +65 -0
  98. package/dist/library/early-cache.js +380 -0
  99. package/dist/library/early-cache.js.map +1 -0
  100. package/dist/library/early-cache.test.d.ts +1 -0
  101. package/dist/library/early-cache.test.js +528 -0
  102. package/dist/library/early-cache.test.js.map +1 -0
  103. package/dist/library/int-infer.js +14 -0
  104. package/dist/library/int-infer.js.map +1 -1
  105. package/dist/library/int-infer.test.js +21 -4
  106. package/dist/library/int-infer.test.js.map +1 -1
  107. package/dist/library/profile.d.ts +3 -0
  108. package/dist/library/profile.js +9 -1
  109. package/dist/library/profile.js.map +1 -1
  110. package/dist/library/semantic-source.d.ts +13 -0
  111. package/dist/library/semantic-source.js +257 -0
  112. package/dist/library/semantic-source.js.map +1 -0
  113. package/dist/library/semantic-source.test.d.ts +1 -0
  114. package/dist/library/semantic-source.test.js +113 -0
  115. package/dist/library/semantic-source.test.js.map +1 -0
  116. package/dist/library/sidecar.d.ts +6 -0
  117. package/dist/library/sidecar.js +11 -0
  118. package/dist/library/sidecar.js.map +1 -1
  119. package/package.json +2 -2
  120. package/surface-manifest.json +1 -1
@@ -8,7 +8,7 @@ import { ARRAY_METHODS, MAP_METHODS, SET_COMBINE_METHODS, SET_METHODS, STR_METHO
8
8
  import { droppableStatic, isRequireMainFilename, lowerDynObjectLiteral, probeLower, pureReemittable } from "./lower-exprs.js";
9
9
  import { forOfVarTarget, lowerDestructuringAssign } from "./lower-stmts.js";
10
10
  import { isJsSourceFile, locOf } from "../program.js";
11
- import { DYN_DISPATCH_METHODS, islandPrimitiveExit } from "./lower-calls.js";
11
+ import { islandPrimitiveExit, lowerDynDispatchMethodCall } from "./lower-calls.js";
12
12
  import { typeKey } from "../types.js";
13
13
  import { dynUndefinedExpr, own } from "./lowerer.js";
14
14
  /** Lower an expression whose checker type is statically `undefined`/`void`.
@@ -142,7 +142,11 @@ export function lowerArrayMethodCall(L, call, access) {
142
142
  {
143
143
  const receiver = L.lowerExpr(access.expression);
144
144
  if (receiver.type.kind === "jsval") {
145
- const args = call.arguments.map((a) => L.jsvalIn(L.lowerExpr(a), a));
145
+ const loweredArgs = call.arguments.map((a) => L.lowerExpr(a));
146
+ if (name === "filter" && loweredArgs[0]?.type.kind === "func" && loweredArgs[0].type.ret.kind === "void") {
147
+ L.unsupported("SC1090", call.arguments[0], "'.filter()' with a void-returning predicate (the callback return value is erased before its truthiness can be tested)");
148
+ }
149
+ const args = loweredArgs.map((arg, i) => L.jsvalIn(arg, call.arguments[i]));
146
150
  const result = { kind: "jsOp", op: "callMethod", name, args: [receiver, ...args], type: JSVAL, loc };
147
151
  return islandPrimitiveExit(L, call, result);
148
152
  }
@@ -155,21 +159,9 @@ export function lowerArrayMethodCall(L, call, access) {
155
159
  // ICE). Consumers validate the dyn result where a static type is
156
160
  // required (dynCheck — the member-read discipline).
157
161
  if (receiver.type.kind === "dyn") {
158
- if (DYN_DISPATCH_METHODS.has(name) && !call.questionDotToken && !access.questionDotToken) {
159
- if (call.arguments.some((a) => ts.isSpreadElement(a))) {
160
- L.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
161
- }
162
- const args = call.arguments.map((a) => L.lowerExprExpecting(a, DYN));
163
- return {
164
- kind: "dynInvoke",
165
- recv: receiver,
166
- method: name,
167
- calleeName: access.getText(),
168
- args,
169
- type: DYN,
170
- loc,
171
- };
172
- }
162
+ const dispatched = lowerDynDispatchMethodCall(L, call, access, receiver, true);
163
+ if (dispatched)
164
+ return dispatched;
173
165
  L.noLowering(`.${name} on an array value held in a checked-dynamic binding`, call, "assign it to an array-typed binding first (the validated extraction), then call the method");
174
166
  }
175
167
  // An evolving-`any` array binding under --dynamic whose flow type
@@ -596,12 +588,64 @@ export function lowerArrayHofCall(L, call, access, method, elem) {
596
588
  // declaration, so the honest answer is the fence).
597
589
  L.unsupported("SC1090", call, "'.map()' with a callback returning 'unknown'-typed values (the result array has no static element type — annotate the callback's return)");
598
590
  }
599
- if (method === "filter" && fnRet.kind !== "bool")
591
+ // JS applies ToBoolean to whatever the predicate answers, so a non-bool
592
+ // result is not an error — the filter loop wraps the call in the same
593
+ // toBool an `if` statement would apply. The island/dyn shapes, whose
594
+ // truthiness needs the engine, and void, whose real answer the ABI has
595
+ // already discarded, keep the fence. No separate
596
+ // requireTruthyUnion call belongs here: its check (no dyn/caught arm)
597
+ // IS filterPredicateOk's union branch, so it could never speak.
598
+ if (method === "filter" && !filterPredicateOk(L, fnRet)) {
599
+ if (fnRet.kind === "void") {
600
+ L.unsupported("SC1090", argNode, "'.filter()' with a void-returning predicate (the callback return value is erased before its truthiness can be tested)");
601
+ }
600
602
  L.badType(argNode, L.typeOf(argNode));
603
+ }
601
604
  const helper = arrayHofHelper(L, method, elem, fnRet, arity, loc);
602
605
  const resultType = method === "map" ? arrayOf(fnRet) : method === "filter" ? arrayOf(elem) : VOID;
603
606
  return { kind: "call", callee: helper, args: [receiver, fnArg], type: resultType, loc };
604
607
  }
608
+ /** The predicate result kinds `.filter()` accepts. JS applies ToBoolean to
609
+ * whatever the callback answers, so a bool is not required: the scalars and
610
+ * the reference kinds have constant or by-value answers, and a union is fine
611
+ * when every arm does. void/dyn/jsval/caught stay out — see below. */
612
+ function filterPredicateOk(L, ret) {
613
+ if (ret.kind === "bool")
614
+ return true;
615
+ // VOID is a TYPE erasure, not a runtime value: TS lets a value-returning
616
+ // function sit in a void-returning slot (`const p: (n: number) => void =
617
+ // (n) => n`), so the predicate's real answer can be truthy while the
618
+ // compiled ABI has already discarded it. Treating void as constantly
619
+ // falsy would silently answer [] where Node answers [1]. Fenced until
620
+ // the returned value can be preserved through the void ABI.
621
+ // dyn/jsval/caught stay out too: no native ToBoolean to compile against.
622
+ if (ret.kind === "void")
623
+ return false;
624
+ if (ret.kind === "dyn" || ret.kind === "jsval" || ret.kind === "caught")
625
+ return false;
626
+ if (ret.kind === "union") {
627
+ const def = L.unions.get(ret.unionId);
628
+ return def !== undefined && def.arms.every((a) => a.kind !== "dyn" && a.kind !== "caught");
629
+ }
630
+ return true;
631
+ }
632
+ /** The filter loop's condition: the predicate's result put through JS
633
+ * ToBoolean. A bool answer is already the condition; everything else takes
634
+ * the same `toBool` wrapper an `if` statement would apply (a union answer
635
+ * routes through its interned per-arm truthy helper). */
636
+ function filterCond(call, fnRet, loc) {
637
+ if (fnRet.kind === "bool")
638
+ return call;
639
+ // No constant-false arm here: void is fenced at the call site, and a
640
+ // bare undefinedT/nullT return cannot arise (mapType sends `undefined`/
641
+ // `void` returns to void and a standalone `null` return to the unit-ONLY
642
+ // UNION, which routes through toBool below; ir/validate.ts rejects a
643
+ // bare unit return type outright). filterPredicateOk already rejected
644
+ // the arms with no native ToBoolean (dyn/caught) — which is exactly what
645
+ // requireTruthyUnion checks — and it did so at the call site, where a
646
+ // real node exists for the diagnostic.
647
+ return { kind: "toBool", operand: call, type: BOOL, loc };
648
+ }
605
649
  /** Interned synthetic loop function for one (method, elem, fnRet, arity)
606
650
  * combo. Named `%arr.<method>.<n>` ('%' keeps it out of the user
607
651
  * namespace); rides `liftedFns` into the module like a lifted lambda (it
@@ -934,7 +978,9 @@ export function buildArrayHofFn(L, name, method, elem, fnRet, arity, loc) {
934
978
  { kind: "varDecl", localId: "v.0", init: getElem, loc },
935
979
  {
936
980
  kind: "if",
937
- cond: callF(ref("v.0", elem)),
981
+ // ToBoolean over the predicate's answer — inert when it already
982
+ // returned bool, the per-union helper when it returned a union.
983
+ cond: filterCond(callF(ref("v.0", elem)), fnRet, loc),
938
984
  then: [push(arrT, ref("v.0", elem))],
939
985
  else_: null,
940
986
  loc,
@@ -5808,6 +5854,7 @@ export function objectIterOverIndexShape(L, node, member, argIr, shape, receiver
5808
5854
  const body = [
5809
5855
  { kind: "varDecl", localId: "out.0", init: { kind: "arrayLit", elems: [], type: resultT, loc }, loc },
5810
5856
  ];
5857
+ const fieldStmts = new Map();
5811
5858
  // Declared fields, in declaration order. Undefined-valued fields
5812
5859
  // skip at runtime (the unset-optional convention); values surface
5813
5860
  // into the element type or the site fences with the field named.
@@ -5875,7 +5922,7 @@ export function objectIterOverIndexShape(L, node, member, argIr, shape, receiver
5875
5922
  loc,
5876
5923
  };
5877
5924
  }
5878
- body.push(utag >= 0 && f.type.kind === "union"
5925
+ const fieldStmt = utag >= 0 && f.type.kind === "union"
5879
5926
  ? {
5880
5927
  kind: "if",
5881
5928
  cond: { kind: "unionIsTag", unionId: f.type.unionId, tag: utag, negated: true, value: raw, type: BOOL, loc },
@@ -5883,7 +5930,9 @@ export function objectIterOverIndexShape(L, node, member, argIr, shape, receiver
5883
5930
  else_: null,
5884
5931
  loc,
5885
5932
  }
5886
- : push(pushed));
5933
+ : push(pushed);
5934
+ fieldStmts.set(f.name, fieldStmt);
5935
+ body.push(fieldStmt);
5887
5936
  }
5888
5937
  // The overflow walk: a fresh key snapshot in JS own-key order, each
5889
5938
  // value read back through the overflow-only keyed read (declared
@@ -5930,8 +5979,9 @@ export function objectIterOverIndexShape(L, node, member, argIr, shape, receiver
5930
5979
  ],
5931
5980
  loc,
5932
5981
  }, { kind: "return", value: outRef, loc });
5982
+ const suffix = body.slice(1 + fieldStmts.size);
5933
5983
  L.arrHofHelpers.set(key, helper);
5934
- L.liftedFns.push({
5984
+ const fn = {
5935
5985
  name: helper,
5936
5986
  params: [{ localId: "r.0", name: "r", type: argIr }],
5937
5987
  returnType: resultT,
@@ -5944,7 +5994,16 @@ export function objectIterOverIndexShape(L, node, member, argIr, shape, receiver
5944
5994
  ],
5945
5995
  body,
5946
5996
  loc,
5997
+ };
5998
+ L.shapeOrderHelperFinalizers.push(() => {
5999
+ const current = L.shapes.get(argIr.shapeId) ?? shape;
6000
+ const currentOrder = current.declaredOrder ?? current.fields.map((f) => f.name);
6001
+ fn.body = [body[0], ...currentOrder.flatMap((name) => {
6002
+ const stmt = fieldStmts.get(name);
6003
+ return stmt ? [stmt] : [];
6004
+ }), ...suffix];
5947
6005
  });
6006
+ L.liftedFns.push(fn);
5948
6007
  }
5949
6008
  return { kind: "call", callee: helper, args: [receiver], type: resultT, loc };
5950
6009
  }
@@ -6310,6 +6369,7 @@ export function lowerRecordOvfCaptureHelper(L, fromId, toId, loc) {
6310
6369
  loc,
6311
6370
  },
6312
6371
  ];
6372
+ const fieldStmts = new Map();
6313
6373
  // Source declared fields in declaration order, skipping unset
6314
6374
  // optionals (stance 37) and the direct-initialized (consumed) names.
6315
6375
  for (const ff of orderedFields) {
@@ -6328,7 +6388,7 @@ export function lowerRecordOvfCaptureHelper(L, fromId, toId, loc) {
6328
6388
  ...(to.fields.some((f) => f.name === ff.name) ? {} : { overflowOnly: true }),
6329
6389
  loc,
6330
6390
  };
6331
- body.push(utag >= 0 && ff.type.kind === "union"
6391
+ const fieldStmt = utag >= 0 && ff.type.kind === "union"
6332
6392
  ? {
6333
6393
  kind: "if",
6334
6394
  cond: { kind: "unionIsTag", unionId: ff.type.unionId, tag: utag, negated: true, value: raw, type: BOOL, loc },
@@ -6336,7 +6396,9 @@ export function lowerRecordOvfCaptureHelper(L, fromId, toId, loc) {
6336
6396
  else_: null,
6337
6397
  loc,
6338
6398
  }
6339
- : write);
6399
+ : write;
6400
+ fieldStmts.set(ff.name, fieldStmt);
6401
+ body.push(fieldStmt);
6340
6402
  }
6341
6403
  // The source overflow, in JS own-key order (only index-signature
6342
6404
  // sources carry one).
@@ -6375,7 +6437,8 @@ export function lowerRecordOvfCaptureHelper(L, fromId, toId, loc) {
6375
6437
  });
6376
6438
  }
6377
6439
  body.push({ kind: "return", value: outRef, loc });
6378
- L.liftedFns.push({
6440
+ const suffix = body.slice(1 + fieldStmts.size);
6441
+ const fn = {
6379
6442
  name,
6380
6443
  params: [{ localId: "s.0", name: "s", type: fromT }],
6381
6444
  returnType: toT,
@@ -6392,7 +6455,16 @@ export function lowerRecordOvfCaptureHelper(L, fromId, toId, loc) {
6392
6455
  ],
6393
6456
  body,
6394
6457
  loc,
6458
+ };
6459
+ L.shapeOrderHelperFinalizers.push(() => {
6460
+ const current = L.shapes.get(fromId) ?? from;
6461
+ const currentOrder = current.declaredOrder ?? current.fields.map((f) => f.name);
6462
+ fn.body = [body[0], ...currentOrder.flatMap((field) => {
6463
+ const stmt = fieldStmts.get(field);
6464
+ return stmt ? [stmt] : [];
6465
+ }), ...suffix];
6395
6466
  });
6467
+ L.liftedFns.push(fn);
6396
6468
  return name;
6397
6469
  }
6398
6470
  /** `Object.assign(target, ...sources)` into an INDEX-SIGNATURE record:
@@ -6485,6 +6557,7 @@ export function lowerObjectAssignIndexShape(L, call) {
6485
6557
  const sRef = ref("s.0", fromT);
6486
6558
  const intoSlot = (v, lift) => lift === "dyn" ? { kind: "dynFrom", value: v, type: DYN, loc } : L.applyWidthLift(lift, v, tIv, loc);
6487
6559
  const body = [];
6560
+ const fieldStmts = new Map();
6488
6561
  for (const ff of plan.fields) {
6489
6562
  const raw = { kind: "recordGet", obj: sRef, shapeId: plan.fromId, field: ff.name, type: ff.type, loc };
6490
6563
  const utag = ff.type.kind === "union" ? L.armTag(ff.type.unionId, UNDEFINED_T) : -1;
@@ -6496,7 +6569,7 @@ export function lowerObjectAssignIndexShape(L, call) {
6496
6569
  value: intoSlot(raw, ff.lift),
6497
6570
  loc,
6498
6571
  };
6499
- body.push(utag >= 0 && ff.type.kind === "union"
6572
+ const fieldStmt = utag >= 0 && ff.type.kind === "union"
6500
6573
  ? {
6501
6574
  kind: "if",
6502
6575
  cond: { kind: "unionIsTag", unionId: ff.type.unionId, tag: utag, negated: true, value: raw, type: BOOL, loc },
@@ -6504,7 +6577,9 @@ export function lowerObjectAssignIndexShape(L, call) {
6504
6577
  else_: null,
6505
6578
  loc,
6506
6579
  }
6507
- : write);
6580
+ : write;
6581
+ fieldStmts.set(ff.name, fieldStmt);
6582
+ body.push(fieldStmt);
6508
6583
  }
6509
6584
  const ksT = arrayOf(STRING);
6510
6585
  const fromShape = L.shapes.get(plan.fromId);
@@ -6542,7 +6617,8 @@ export function lowerObjectAssignIndexShape(L, call) {
6542
6617
  });
6543
6618
  }
6544
6619
  body.push({ kind: "return", value: tRef, loc });
6545
- L.liftedFns.push({
6620
+ const suffix = body.slice(fieldStmts.size);
6621
+ const fn = {
6546
6622
  name,
6547
6623
  params: [
6548
6624
  { localId: "t.0", name: "t", type: toT },
@@ -6562,7 +6638,16 @@ export function lowerObjectAssignIndexShape(L, call) {
6562
6638
  ],
6563
6639
  body,
6564
6640
  loc,
6641
+ };
6642
+ L.shapeOrderHelperFinalizers.push(() => {
6643
+ const current = L.shapes.get(plan.fromId) ?? fromShape;
6644
+ const currentOrder = current.declaredOrder ?? current.fields.map((f) => f.name);
6645
+ fn.body = [...currentOrder.flatMap((field) => {
6646
+ const stmt = fieldStmts.get(field);
6647
+ return stmt ? [stmt] : [];
6648
+ }), ...suffix];
6565
6649
  });
6650
+ L.liftedFns.push(fn);
6566
6651
  return name;
6567
6652
  };
6568
6653
  let acc = L.lowerExprExpecting(call.arguments[0], targetIr);